From 7a7f610f83a6dcbaeeecd2e1ec45ad3a37626d09 Mon Sep 17 00:00:00 2001 From: Malemna Swari Tarigan Date: Thu, 19 Jun 2025 15:39:21 +0700 Subject: [PATCH] Add Projek TA --- TA_API/.editorconfig | 18 + TA_API/.env.example | 70 + TA_API/.gitattributes | 11 + TA_API/.gitignore | 23 + TA_API/.htaccess | 14 + TA_API/EMAIL_VERIFICATION_DOC.md | 172 + TA_API/README.md | 106 + TA_API/RESET_PASSWORD_DOC.md | 207 + TA_API/_ide_helper.php | 27146 +++++++++++++++ TA_API/_ide_helper_models.php | 396 + .../Api/AdminDashboardController.php | 115 + .../Api/AdminWithdrawalController.php | 220 + .../Http/Controllers/Api/AuthController.php | 479 + .../Http/Controllers/Api/BaseController.php | 49 + .../Controllers/Api/BookingController.php | 1091 + .../Controllers/Api/CustomerController.php | 280 + .../Api/DocumentationController.php | 47 + .../Api/EmailVerificationController.php | 101 + .../Api/ForgotPasswordController.php | 126 + .../Controllers/Api/MidtransController.php | 330 + .../Http/Controllers/Api/RatingController.php | 110 + .../Api/TailorCalendarController.php | 207 + .../Http/Controllers/Api/TailorController.php | 268 + .../Api/TailorDashboardController.php | 62 + .../Api/TailorGalleryController.php | 168 + .../Api/TailorProfileController.php | 121 + .../Api/TailorSearchController.php | 483 + .../Api/TailorServiceController.php | 183 + .../Api/TailorSpecializationController.php | 416 + .../Http/Controllers/Api/WalletController.php | 164 + .../Http/Controllers/BookingController.php | 1 + TA_API/app/Http/Controllers/Controller.php | 8 + .../Http/Controllers/FileAccessController.php | 88 + TA_API/app/Http/Kernel.php | 57 + TA_API/app/Http/Middleware/CheckRole.php | 28 + TA_API/app/Http/Middleware/CorsMiddleware.php | 39 + TA_API/app/Models.zip | Bin 0 -> 6804 bytes TA_API/app/Models/BankAccount.php | 37 + TA_API/app/Models/Booking.php | 105 + TA_API/app/Models/TailorGallery.php | 32 + TA_API/app/Models/TailorRating.php | 51 + TA_API/app/Models/TailorService.php | 38 + TA_API/app/Models/TailorSpecialization.php | 29 + TA_API/app/Models/User.php | 190 + TA_API/app/Models/Wallet.php | 67 + TA_API/app/Models/WalletTransaction.php | 37 + TA_API/app/Models/Withdrawal.php | 39 + .../ResetPasswordNotification.php | 62 + .../Notifications/VerifyEmailNotification.php | 65 + TA_API/app/Providers/AppServiceProvider.php | 28 + TA_API/app/Providers/AuthServiceProvider.php | 39 + TA_API/app/Providers/EventServiceProvider.php | 38 + TA_API/app/Providers/RouteServiceProvider.php | 40 + TA_API/artisan | 18 + TA_API/bacaini.md | 578 + TA_API/bootstrap/app.php | 18 + TA_API/bootstrap/cache/.gitignore | 2 + TA_API/bootstrap/providers.php | 5 + TA_API/composer.json | 74 + TA_API/composer.lock | 8499 +++++ TA_API/config/app.php | 189 + TA_API/config/auth.php | 115 + TA_API/config/cache.php | 108 + TA_API/config/database.php | 177 + TA_API/config/filesystems.php | 80 + TA_API/config/ide-helper.php | 352 + TA_API/config/logging.php | 132 + TA_API/config/mail.php | 116 + TA_API/config/queue.php | 112 + TA_API/config/sanctum.php | 83 + TA_API/config/services.php | 38 + TA_API/config/session.php | 217 + TA_API/database/.gitignore | 1 + TA_API/database/factories/UserFactory.php | 44 + .../0001_01_01_000001_create_cache_table.php | 35 + .../0001_01_01_000002_create_jobs_table.php | 57 + .../2014_10_12_000000_create_users_table.php | 37 + ...23_000000_create_tailor_services_table.php | 35 + .../2024_03_23_create_bookings_table.php | 43 + ...2024_03_23_create_tailor_ratings_table.php | 35 + ...23_create_tailor_specializations_table.php | 50 + ...24_03_27_create_tailor_galleries_table.php | 32 + ..._add_completion_date_to_bookings_table.php | 28 + ...18_000000_create_password_resets_table.php | 28 + ...ethod_and_transaction_code_to_bookings.php | 30 + ...00000_change_payment_method_to_varchar.php | 41 + ...2024_05_03_000001_create_wallets_table.php | 24 + ...5_03_000002_create_bank_accounts_table.php | 28 + ...00003_create_wallet_transactions_table.php | 27 + ..._05_03_000004_create_withdrawals_table.php | 28 + ...025_03_23_110103_create_sessions_table.php | 31 + ...34_create_personal_access_tokens_table.php | 33 + ...708_add_measurements_to_bookings_table.php | 28 + ...140_add_measurements_to_bookings_table.php | 53 + ...3_create_customer_specialization_table.php | 32 + ..._061144_add_coordinates_to_users_table.php | 29 + ...add_category_to_tailor_specializations.php | 28 + ...29_add_photo_to_tailor_specializations.php | 28 + ..._photo_to_tailor_specializations_table.php | 28 + ...2729_add_pickup_date_to_bookings_table.php | 28 + ...2735_add_pickup_date_to_bookings_table.php | 28 + ...606_create_password_reset_tokens_table.php | 28 + ...ayment_status_column_in_bookings_table.php | 40 + ..._add_midtrans_fields_to_bookings_table.php | 28 + TA_API/database/seeders/AdminUserSeeder.php | 25 + TA_API/database/seeders/DatabaseSeeder.php | 164 + .../seeders/TailorSpecializationSeeder.php | 40 + TA_API/docs/wallet-api.md | 483 + TA_API/documentation.md | 1081 + TA_API/package.json | 16 + TA_API/phpunit.xml | 33 + TA_API/postman_collection.json | 298 + TA_API/project_jahit.sql | 636 + TA_API/public/.htaccess | 47 + TA_API/public/favicon.ico | 0 TA_API/public/images/LogoGelap.png | Bin 0 -> 5999 bytes TA_API/public/images/logo.png | Bin 0 -> 6166 bytes TA_API/public/index.php | 20 + TA_API/public/robots.txt | 2 + TA_API/resources/css/app.css | 11 + TA_API/resources/js/app.js | 1 + TA_API/resources/js/bootstrap.js | 4 + .../views/api-docs-original.blade.php | 1554 + TA_API/resources/views/api-docs.blade.php | 2489 ++ .../views/emails/reset-password.blade.php | 111 + .../views/emails/verification-error.blade.php | 140 + .../emails/verification-success.blade.php | 122 + .../views/emails/verify-email.blade.php | 108 + .../views/wallet-endpoints.blade.php | 438 + TA_API/resources/views/welcome.blade.php | 277 + TA_API/routes/api.php | 241 + TA_API/routes/console.php | 8 + TA_API/routes/web.php | 43 + TA_API/storage/app/.gitignore | 4 + TA_API/storage/app/private/.gitignore | 2 + TA_API/storage/app/public/.gitignore | 2 + TA_API/storage/framework/.gitignore | 9 + TA_API/storage/framework/cache/.gitignore | 3 + .../storage/framework/cache/data/.gitignore | 2 + TA_API/storage/framework/sessions/.gitignore | 2 + TA_API/storage/framework/testing/.gitignore | 2 + TA_API/storage/framework/views/.gitignore | 2 + TA_API/storage/logs/.gitignore | 2 + TA_API/test-access.php | 25 + TA_API/tests/Feature/ExampleTest.php | 19 + TA_API/tests/TestCase.php | 10 + TA_API/tests/Unit/ExampleTest.php | 16 + TA_API/vite.config.js | 13 + TA_android/.env | 12 + TA_android/.gitignore | 43 + TA_android/.metadata | 30 + TA_android/.vscode/settings.json | 6 + TA_android/README.md | 16 + TA_android/analysis_options.yaml | 36 + TA_android/android/.gitignore | 14 + TA_android/android/app/build.gradle.kts | 44 + .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 88 + .../com/example/tailorhub/MainActivity.kt | 5 + .../drawable-hdpi/ic_launcher_foreground.png | Bin 0 -> 3577 bytes .../drawable-mdpi/ic_launcher_foreground.png | Bin 0 -> 2615 bytes .../res/drawable-v21/launch_background.xml | 12 + .../drawable-xhdpi/ic_launcher_foreground.png | Bin 0 -> 4776 bytes .../ic_launcher_foreground.png | Bin 0 -> 6828 bytes .../ic_launcher_foreground.png | Bin 0 -> 17838 bytes .../main/res/drawable/launch_background.xml | 12 + .../res/mipmap-anydpi-v26/launcher_icon.xml | 9 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../main/res/mipmap-hdpi/launcher_icon.png | Bin 0 -> 1903 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../main/res/mipmap-mdpi/launcher_icon.png | Bin 0 -> 1346 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xhdpi/launcher_icon.png | Bin 0 -> 2517 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxhdpi/launcher_icon.png | Bin 0 -> 3508 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../main/res/mipmap-xxxhdpi/launcher_icon.png | Bin 0 -> 4394 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/colors.xml | 4 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + TA_android/android/build.gradle.kts | 21 + TA_android/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + TA_android/android/settings.gradle.kts | 25 + TA_android/assets/.env | 6 + TA_android/assets/images/LogoGelap.png | Bin 0 -> 5999 bytes TA_android/assets/images/LogoPutih.png | Bin 0 -> 6166 bytes TA_android/assets/images/avatar_default.png | Bin 0 -> 88197 bytes .../assets/images/model_jahit/celana.png | Bin 0 -> 2216 bytes .../assets/images/model_jahit/gamis.png | Bin 0 -> 4937 bytes TA_android/assets/images/model_jahit/gaun.png | Bin 0 -> 3576 bytes .../assets/images/model_jahit/jasblezer.png | Bin 0 -> 2939 bytes .../assets/images/model_jahit/kebaya.png | Bin 0 -> 7289 bytes .../assets/images/model_jahit/kemeja.png | Bin 0 -> 4962 bytes TA_android/assets/images/model_jahit/rok.png | Bin 0 -> 3086 bytes .../assets/images/model_jahit/seragam.png | Bin 0 -> 3784 bytes TA_android/assets/images/no_location.png | Bin 0 -> 27399 bytes TA_android/assets/images/payment/amex.png | Bin 0 -> 19320 bytes TA_android/assets/images/payment/bca.png | Bin 0 -> 95653 bytes TA_android/assets/images/payment/bni.png | Bin 0 -> 49369 bytes TA_android/assets/images/payment/mandiri.png | Bin 0 -> 79698 bytes .../assets/images/payment/mastercard.png | Bin 0 -> 20512 bytes TA_android/assets/images/payment/visa.png | Bin 0 -> 95068 bytes TA_android/assets/images/payment_new/amex.png | Bin 0 -> 19320 bytes TA_android/assets/images/payment_new/bca.png | Bin 0 -> 95653 bytes TA_android/assets/images/payment_new/bni.png | Bin 0 -> 49369 bytes .../assets/images/payment_new/mandiri.png | Bin 0 -> 79698 bytes .../assets/images/payment_new/mastercard.png | Bin 0 -> 20512 bytes TA_android/assets/images/payment_new/visa.png | Bin 0 -> 95068 bytes TA_android/assets/images/tailor_1.png | Bin 0 -> 8661 bytes TA_android/assets/images/tailor_2.png | Bin 0 -> 8661 bytes TA_android/assets/images/tailor_3.png | Bin 0 -> 8661 bytes TA_android/assets/images/tailor_4.png | Bin 0 -> 8661 bytes TA_android/assets/images/tailor_5.png | Bin 0 -> 8661 bytes TA_android/assets/images/tailor_6.png | Bin 0 -> 8661 bytes TA_android/assets/images/tailor_banner.png | Bin 0 -> 556451 bytes TA_android/assets/images/tailor_banner2.png | Bin 0 -> 540019 bytes TA_android/assets/images/tailor_banner3.png | Bin 0 -> 9213 bytes TA_android/assets/images/tailor_default.png | Bin 0 -> 88197 bytes TA_android/ios/.gitignore | 34 + TA_android/ios/Flutter/AppFrameworkInfo.plist | 26 + TA_android/ios/Flutter/Debug.xcconfig | 1 + TA_android/ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 616 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + TA_android/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 1 + .../Icon-App-1024x1024@1x.png | Bin 0 -> 5334 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 86 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 104 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 146 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 97 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 144 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 228 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 104 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 174 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 342 bytes .../AppIcon.appiconset/Icon-App-50x50@1x.png | Bin 0 -> 133 bytes .../AppIcon.appiconset/Icon-App-50x50@2x.png | Bin 0 -> 289 bytes .../AppIcon.appiconset/Icon-App-57x57@1x.png | Bin 0 -> 145 bytes .../AppIcon.appiconset/Icon-App-57x57@2x.png | Bin 0 -> 330 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 342 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 493 bytes .../AppIcon.appiconset/Icon-App-72x72@1x.png | Bin 0 -> 166 bytes .../AppIcon.appiconset/Icon-App-72x72@2x.png | Bin 0 -> 412 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 169 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 430 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 462 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + TA_android/ios/Runner/Info.plist | 57 + .../ios/Runner/Runner-Bridging-Header.h | 1 + TA_android/ios/RunnerTests/RunnerTests.swift | 12 + .../lib/core/controllers/auth_controller.dart | 980 + .../core/controllers/booking_controller.dart | 217 + .../core/controllers/category_controller.dart | 76 + .../core/controllers/gallery_controller.dart | 218 + .../core/controllers/midtrans_controller.dart | 275 + .../core/controllers/order_controller.dart | 38 + .../core/controllers/profile_controller.dart | 566 + .../controllers/wallet_wd_controller.dart | 345 + TA_android/lib/core/models/booking_model.dart | 536 + .../lib/core/models/gallery_item_model.dart | 47 + TA_android/lib/core/models/gallery_model.dart | 37 + TA_android/lib/core/models/order_model.dart | 17 + TA_android/lib/core/models/review_model.dart | 54 + .../lib/core/models/specialization_model.dart | 96 + TA_android/lib/core/models/tailor_model.dart | 271 + TA_android/lib/core/models/user_model.dart | 185 + TA_android/lib/core/models/wallet_model.dart | 121 + .../core/models/wallet_transaction_model.dart | 186 + .../lib/core/models/withdrawals_model.dart | 0 .../lib/core/providers/user_provider.dart | 200 + TA_android/lib/core/routes/routes.dart | 156 + TA_android/lib/core/services/api_service.dart | 3234 ++ .../lib/core/services/auth_service.dart | 50 + .../lib/core/services/booking_service.dart | 302 + .../services/forgot_passowrd_service.dart | 139 + .../lib/core/services/midtrans_service.dart | 195 + .../core/services/midtrans_service.dart.bak | 152 + .../core/services/midtrans_service.dart.temp | 152 + .../lib/core/services/profile_service.dart | 211 + .../lib/core/services/search_service.dart | 55 + .../core/services/shared_prefs_helper.dart | 95 + .../lib/core/services/wallet_wd_service.dart | 265 + TA_android/lib/core/theme/colors.dart | 13 + TA_android/lib/core/utils/app_routes.dart | 9 + TA_android/lib/core/utils/logger.dart | 104 + TA_android/lib/core/utils/url_helper.dart | 109 + .../lib/core/widgets/category_card.dart | 420 + .../lib/core/widgets/custom_button.dart | 57 + .../lib/core/widgets/custom_text_field.dart | 73 + .../lib/core/widgets/dropdown_field.dart | 47 + .../lib/core/widgets/gallery_grid_widget.dart | 237 + .../lib/core/widgets/image_upload_field.dart | 121 + TA_android/lib/core/widgets/label_text.dart | 29 + .../core/widgets/location_picker_dialog.dart | 195 + .../lib/core/widgets/location_picker_map.dart | 229 + .../core/widgets/multiline_text_field.dart | 37 + .../lib/core/widgets/password_field.dart | 66 + .../lib/core/widgets/success_dialog.dart | 65 + TA_android/lib/core/widgets/tailor_card.dart | 183 + .../wallet/widgets/add_bank_account_form.dart | 204 + TA_android/lib/main.dart | 141 + .../auth/forgot_password_customer_page.dart | 485 + .../lib/pages/auth/forgot_password_page.dart | 162 + .../auth/forgot_password_tailor_page.dart | 365 + TA_android/lib/pages/auth/login_page.dart | 217 + .../lib/pages/auth/login_tailor_page.dart | 218 + .../pages/auth/register_customer_page.dart | 542 + .../lib/pages/auth/register_tailor_page.dart | 453 + .../lib/pages/clothing_category_page.dart | 678 + .../lib/pages/costumer/home/booking_page.dart | 1132 + .../pages/costumer/home/description_page.dart | 707 + .../lib/pages/costumer/home/home_page.dart | 506 + .../lib/pages/costumer/home/review_page.dart | 149 + .../lib/pages/costumer/home/search_page.dart | 207 + TA_android/lib/pages/costumer/main_page.dart | 118 + .../costumer/order/midtrans_webview_page.dart | 241 + .../costumer/order/order_detail_page.dart | 3099 ++ .../lib/pages/costumer/order/order_page.dart | 1468 + .../pages/costumer/order/payment_page.dart | 853 + .../pages/costumer/profile/profile_page.dart | 691 + TA_android/lib/pages/debug/debug_page.dart | 370 + TA_android/lib/pages/onboarding_page.dart | 164 + .../lib/pages/register_option_page.dart | 207 + TA_android/lib/pages/splash_screen.dart | 107 + .../lib/pages/tailor/home/home_page.dart | 797 + TA_android/lib/pages/tailor/main_page.dart | 116 + .../pages/tailor/order/order_detail_Page.dart | 3645 ++ .../lib/pages/tailor/order/order_page.dart | 1371 + .../lib/pages/tailor/order/temp_edit.dart | 1 + .../tailor/order/temp_reject_booking.dart | 106 + .../pages/tailor/profile/profile_page.dart | 1334 + .../pages/tailor/schedule/schedule_page.dart | 503 + .../tailor/wallet/add_bank_account_page.dart | 508 + .../tailor/wallet/wallet_history_page.dart | 1062 + .../pages/tailor/wallet/withdrawal_page.dart | 922 + TA_android/linux/.gitignore | 1 + TA_android/linux/CMakeLists.txt | 145 + TA_android/linux/flutter/CMakeLists.txt | 88 + .../flutter/generated_plugin_registrant.cc | 19 + .../flutter/generated_plugin_registrant.h | 15 + .../linux/flutter/generated_plugins.cmake | 25 + TA_android/linux/main.cc | 6 + TA_android/linux/my_application.cc | 124 + TA_android/linux/my_application.h | 18 + TA_android/linux/runner/CMakeLists.txt | 26 + TA_android/linux/runner/main.cc | 6 + TA_android/linux/runner/my_application.cc | 130 + TA_android/linux/runner/my_application.h | 18 + TA_android/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 1 + .../macos/Flutter/Flutter-Release.xcconfig | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 26 + .../macos/Runner.xcodeproj/project.pbxproj | 705 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + TA_android/macos/Runner/AppDelegate.swift | 9 + .../AppIcon.appiconset/Contents.json | 68 + .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2218 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 + .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 12 + TA_android/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 15 + TA_android/macos/Runner/Release.entitlements | 8 + .../macos/RunnerTests/RunnerTests.swift | 12 + TA_android/pubspec.lock | 1090 + TA_android/pubspec.yaml | 131 + TA_android/temp_gallery_method.txt | 47 + TA_android/test/widget_test.dart | 30 + TA_android/web/favicon.png | Bin 0 -> 917 bytes TA_android/web/icons/Icon-192.png | Bin 0 -> 5292 bytes TA_android/web/icons/Icon-512.png | Bin 0 -> 8252 bytes TA_android/web/icons/Icon-maskable-192.png | Bin 0 -> 5594 bytes TA_android/web/icons/Icon-maskable-512.png | Bin 0 -> 20998 bytes TA_android/web/index.html | 38 + TA_android/web/manifest.json | 35 + TA_android/windows/.gitignore | 17 + TA_android/windows/CMakeLists.txt | 108 + TA_android/windows/flutter/CMakeLists.txt | 109 + .../flutter/generated_plugin_registrant.cc | 23 + .../flutter/generated_plugin_registrant.h | 15 + .../windows/flutter/generated_plugins.cmake | 27 + TA_android/windows/runner/CMakeLists.txt | 40 + TA_android/windows/runner/Runner.rc | 121 + TA_android/windows/runner/flutter_window.cpp | 71 + TA_android/windows/runner/flutter_window.h | 33 + TA_android/windows/runner/main.cpp | 43 + TA_android/windows/runner/resource.h | 16 + .../windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes TA_android/windows/runner/runner.exe.manifest | 14 + TA_android/windows/runner/utils.cpp | 65 + TA_android/windows/runner/utils.h | 19 + TA_android/windows/runner/win32_window.cpp | 288 + TA_android/windows/runner/win32_window.h | 102 + TA_website/.editorconfig | 18 + TA_website/.env.example | 65 + TA_website/.gitattributes | 11 + TA_website/.gitignore | 23 + TA_website/README.md | 66 + TA_website/_ide_helper.php | 27492 ++++++++++++++++ TA_website/_ide_helper_models.php | 236 + .../Http/Controllers/Admin/AuthController.php | 143 + .../Admin/BankAccountController.php | 291 + .../Controllers/Admin/BookingController.php | 14 + .../Controllers/Admin/CustomerController.php | 114 + .../Controllers/Admin/DashboardController.php | 101 + .../Controllers/Admin/LoginController.php | 113 + .../Admin/SpecializationController.php | 65 + .../Controllers/Admin/TailorController.php | 257 + .../Admin/WithdrawalController.php | 257 + .../app/Http/Controllers/AdminController.php | 54 + .../app/Http/Controllers/Controller.php | 8 + .../app/Http/Middleware/AdminMiddleware.php | 44 + .../app/Http/Middleware/Authenticate.php | 20 + .../Middleware/RedirectIfAuthenticated.php | 30 + TA_website/app/Models/Booking.php | 42 + TA_website/app/Models/Measurement.php | 49 + TA_website/app/Models/Order.php | 42 + TA_website/app/Models/Product.php | 41 + TA_website/app/Models/TailorGallery.php | 24 + TA_website/app/Models/TailorRating.php | 38 + TA_website/app/Models/User.php | 89 + .../app/Providers/ApiServiceProvider.php | 1 + .../app/Providers/AppServiceProvider.php | 28 + .../app/Providers/RouteServiceProvider.php | 40 + TA_website/app/Services/ApiService.php | 171 + TA_website/artisan | 18 + TA_website/bootstrap/app.php | 20 + TA_website/bootstrap/cache/.gitignore | 2 + TA_website/bootstrap/providers.php | 5 + TA_website/composer.json | 73 + TA_website/composer.lock | 8439 +++++ TA_website/config/api.php | 24 + TA_website/config/app.php | 126 + TA_website/config/auth.php | 127 + TA_website/config/cache.php | 108 + TA_website/config/database.php | 174 + TA_website/config/filesystems.php | 80 + TA_website/config/logging.php | 132 + TA_website/config/mail.php | 116 + TA_website/config/queue.php | 112 + TA_website/config/services.php | 38 + TA_website/config/session.php | 217 + TA_website/database/.gitignore | 1 + TA_website/database/factories/UserFactory.php | 44 + .../0001_01_01_000000_create_users_table.php | 49 + .../0001_01_01_000001_create_cache_table.php | 35 + .../0001_01_01_000002_create_jobs_table.php | 57 + ..._000000_add_role_column_to_users_table.php | 44 + TA_website/database/schema/mysql-schema.sql | 136 + .../database/seeders/DatabaseSeeder.php | 23 + TA_website/package.json | 16 + TA_website/phpunit.xml | 33 + TA_website/project_jahit (3).sql | 699 + TA_website/public/.htaccess | 25 + TA_website/public/favicon.ico | 0 TA_website/public/image/LogoGelap.png | Bin 0 -> 5999 bytes TA_website/public/image/LogoPutih.png | Bin 0 -> 6166 bytes TA_website/public/index.php | 20 + TA_website/public/robots.txt | 2 + TA_website/resources/css/app.css | 11 + TA_website/resources/js/api.js | 98 + TA_website/resources/js/app.js | 1 + TA_website/resources/js/bootstrap.js | 15 + TA_website/resources/js/config.js | 23 + TA_website/resources/js/utils.js | 19 + .../views/admin/auth/login.blade.php | 110 + .../admin/bank-accounts/detail.blade.php | 147 + .../admin/bank-accounts/pending.blade.php | 76 + .../admin/bank-accounts/verified.blade.php | 118 + .../admin/bank-accounts/verify.blade.php | 105 + .../views/admin/bookings/index.blade.php | 363 + .../views/admin/customers/index.blade.php | 1132 + .../resources/views/admin/dashboard.blade.php | 314 + .../resources/views/admin/js/config.blade.php | 16 + .../views/admin/layouts/admin.blade.php | 5 + .../views/admin/layouts/app.blade.php | 85 + .../views/admin/layouts/sidebar.blade.php | 146 + .../admin/specializations/index.blade.php | 496 + .../views/admin/tailors/index.blade.php | 977 + .../views/admin/user/admin.blade.php | 465 + .../views/admin/withdrawals/history.blade.php | 363 + .../views/admin/withdrawals/pending.blade.php | 76 + .../views/admin/withdrawals/process.blade.php | 120 + TA_website/resources/views/welcome.blade.php | 277 + TA_website/routes/console.php | 8 + TA_website/routes/web.php | 56 + TA_website/storage/app/.gitignore | 4 + TA_website/storage/app/private/.gitignore | 2 + TA_website/storage/app/public/.gitignore | 2 + TA_website/storage/framework/.gitignore | 9 + TA_website/storage/framework/cache/.gitignore | 3 + .../storage/framework/cache/data/.gitignore | 2 + .../storage/framework/sessions/.gitignore | 2 + .../storage/framework/testing/.gitignore | 2 + TA_website/storage/framework/views/.gitignore | 2 + TA_website/storage/logs/.gitignore | 2 + TA_website/tests/Feature/ExampleTest.php | 19 + TA_website/tests/TestCase.php | 10 + TA_website/tests/Unit/ExampleTest.php | 16 + TA_website/vite.config.js | 13 + 527 files changed, 142702 insertions(+) create mode 100644 TA_API/.editorconfig create mode 100644 TA_API/.env.example create mode 100644 TA_API/.gitattributes create mode 100644 TA_API/.gitignore create mode 100644 TA_API/.htaccess create mode 100644 TA_API/EMAIL_VERIFICATION_DOC.md create mode 100644 TA_API/README.md create mode 100644 TA_API/RESET_PASSWORD_DOC.md create mode 100644 TA_API/_ide_helper.php create mode 100644 TA_API/_ide_helper_models.php create mode 100644 TA_API/app/Http/Controllers/Api/AdminDashboardController.php create mode 100644 TA_API/app/Http/Controllers/Api/AdminWithdrawalController.php create mode 100644 TA_API/app/Http/Controllers/Api/AuthController.php create mode 100644 TA_API/app/Http/Controllers/Api/BaseController.php create mode 100644 TA_API/app/Http/Controllers/Api/BookingController.php create mode 100644 TA_API/app/Http/Controllers/Api/CustomerController.php create mode 100644 TA_API/app/Http/Controllers/Api/DocumentationController.php create mode 100644 TA_API/app/Http/Controllers/Api/EmailVerificationController.php create mode 100644 TA_API/app/Http/Controllers/Api/ForgotPasswordController.php create mode 100644 TA_API/app/Http/Controllers/Api/MidtransController.php create mode 100644 TA_API/app/Http/Controllers/Api/RatingController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorCalendarController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorDashboardController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorGalleryController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorProfileController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorSearchController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorServiceController.php create mode 100644 TA_API/app/Http/Controllers/Api/TailorSpecializationController.php create mode 100644 TA_API/app/Http/Controllers/Api/WalletController.php create mode 100644 TA_API/app/Http/Controllers/BookingController.php create mode 100644 TA_API/app/Http/Controllers/Controller.php create mode 100644 TA_API/app/Http/Controllers/FileAccessController.php create mode 100644 TA_API/app/Http/Kernel.php create mode 100644 TA_API/app/Http/Middleware/CheckRole.php create mode 100644 TA_API/app/Http/Middleware/CorsMiddleware.php create mode 100644 TA_API/app/Models.zip create mode 100644 TA_API/app/Models/BankAccount.php create mode 100644 TA_API/app/Models/Booking.php create mode 100644 TA_API/app/Models/TailorGallery.php create mode 100644 TA_API/app/Models/TailorRating.php create mode 100644 TA_API/app/Models/TailorService.php create mode 100644 TA_API/app/Models/TailorSpecialization.php create mode 100644 TA_API/app/Models/User.php create mode 100644 TA_API/app/Models/Wallet.php create mode 100644 TA_API/app/Models/WalletTransaction.php create mode 100644 TA_API/app/Models/Withdrawal.php create mode 100644 TA_API/app/Notifications/ResetPasswordNotification.php create mode 100644 TA_API/app/Notifications/VerifyEmailNotification.php create mode 100644 TA_API/app/Providers/AppServiceProvider.php create mode 100644 TA_API/app/Providers/AuthServiceProvider.php create mode 100644 TA_API/app/Providers/EventServiceProvider.php create mode 100644 TA_API/app/Providers/RouteServiceProvider.php create mode 100644 TA_API/artisan create mode 100644 TA_API/bacaini.md create mode 100644 TA_API/bootstrap/app.php create mode 100644 TA_API/bootstrap/cache/.gitignore create mode 100644 TA_API/bootstrap/providers.php create mode 100644 TA_API/composer.json create mode 100644 TA_API/composer.lock create mode 100644 TA_API/config/app.php create mode 100644 TA_API/config/auth.php create mode 100644 TA_API/config/cache.php create mode 100644 TA_API/config/database.php create mode 100644 TA_API/config/filesystems.php create mode 100644 TA_API/config/ide-helper.php create mode 100644 TA_API/config/logging.php create mode 100644 TA_API/config/mail.php create mode 100644 TA_API/config/queue.php create mode 100644 TA_API/config/sanctum.php create mode 100644 TA_API/config/services.php create mode 100644 TA_API/config/session.php create mode 100644 TA_API/database/.gitignore create mode 100644 TA_API/database/factories/UserFactory.php create mode 100644 TA_API/database/migrations/0001_01_01_000001_create_cache_table.php create mode 100644 TA_API/database/migrations/0001_01_01_000002_create_jobs_table.php create mode 100644 TA_API/database/migrations/2014_10_12_000000_create_users_table.php create mode 100644 TA_API/database/migrations/2024_03_23_000000_create_tailor_services_table.php create mode 100644 TA_API/database/migrations/2024_03_23_create_bookings_table.php create mode 100644 TA_API/database/migrations/2024_03_23_create_tailor_ratings_table.php create mode 100644 TA_API/database/migrations/2024_03_23_create_tailor_specializations_table.php create mode 100644 TA_API/database/migrations/2024_03_27_create_tailor_galleries_table.php create mode 100644 TA_API/database/migrations/2024_04_07_082735_add_completion_date_to_bookings_table.php create mode 100644 TA_API/database/migrations/2024_04_18_000000_create_password_resets_table.php create mode 100644 TA_API/database/migrations/2024_04_19_000000_add_payment_method_and_transaction_code_to_bookings.php create mode 100644 TA_API/database/migrations/2024_04_19_100000_change_payment_method_to_varchar.php create mode 100644 TA_API/database/migrations/2024_05_03_000001_create_wallets_table.php create mode 100644 TA_API/database/migrations/2024_05_03_000002_create_bank_accounts_table.php create mode 100644 TA_API/database/migrations/2024_05_03_000003_create_wallet_transactions_table.php create mode 100644 TA_API/database/migrations/2024_05_03_000004_create_withdrawals_table.php create mode 100644 TA_API/database/migrations/2025_03_23_110103_create_sessions_table.php create mode 100644 TA_API/database/migrations/2025_03_23_112534_create_personal_access_tokens_table.php create mode 100644 TA_API/database/migrations/2025_03_25_052708_add_measurements_to_bookings_table.php create mode 100644 TA_API/database/migrations/2025_03_25_053140_add_measurements_to_bookings_table.php create mode 100644 TA_API/database/migrations/2025_03_25_061103_create_customer_specialization_table.php create mode 100644 TA_API/database/migrations/2025_03_25_061144_add_coordinates_to_users_table.php create mode 100644 TA_API/database/migrations/2025_04_06_171929_add_category_to_tailor_specializations.php create mode 100644 TA_API/database/migrations/2025_04_06_172929_add_photo_to_tailor_specializations.php create mode 100644 TA_API/database/migrations/2025_04_06_185502_add_photo_to_tailor_specializations_table.php create mode 100644 TA_API/database/migrations/2025_04_07_082729_add_pickup_date_to_bookings_table.php create mode 100644 TA_API/database/migrations/2025_04_07_082735_add_pickup_date_to_bookings_table.php create mode 100644 TA_API/database/migrations/2025_04_18_035606_create_password_reset_tokens_table.php create mode 100644 TA_API/database/migrations/2025_05_02_030041_change_payment_status_column_in_bookings_table.php create mode 100644 TA_API/database/migrations/2025_05_02_031914_add_midtrans_fields_to_bookings_table.php create mode 100644 TA_API/database/seeders/AdminUserSeeder.php create mode 100644 TA_API/database/seeders/DatabaseSeeder.php create mode 100644 TA_API/database/seeders/TailorSpecializationSeeder.php create mode 100644 TA_API/docs/wallet-api.md create mode 100644 TA_API/documentation.md create mode 100644 TA_API/package.json create mode 100644 TA_API/phpunit.xml create mode 100644 TA_API/postman_collection.json create mode 100644 TA_API/project_jahit.sql create mode 100644 TA_API/public/.htaccess create mode 100644 TA_API/public/favicon.ico create mode 100644 TA_API/public/images/LogoGelap.png create mode 100644 TA_API/public/images/logo.png create mode 100644 TA_API/public/index.php create mode 100644 TA_API/public/robots.txt create mode 100644 TA_API/resources/css/app.css create mode 100644 TA_API/resources/js/app.js create mode 100644 TA_API/resources/js/bootstrap.js create mode 100644 TA_API/resources/views/api-docs-original.blade.php create mode 100644 TA_API/resources/views/api-docs.blade.php create mode 100644 TA_API/resources/views/emails/reset-password.blade.php create mode 100644 TA_API/resources/views/emails/verification-error.blade.php create mode 100644 TA_API/resources/views/emails/verification-success.blade.php create mode 100644 TA_API/resources/views/emails/verify-email.blade.php create mode 100644 TA_API/resources/views/wallet-endpoints.blade.php create mode 100644 TA_API/resources/views/welcome.blade.php create mode 100644 TA_API/routes/api.php create mode 100644 TA_API/routes/console.php create mode 100644 TA_API/routes/web.php create mode 100644 TA_API/storage/app/.gitignore create mode 100644 TA_API/storage/app/private/.gitignore create mode 100644 TA_API/storage/app/public/.gitignore create mode 100644 TA_API/storage/framework/.gitignore create mode 100644 TA_API/storage/framework/cache/.gitignore create mode 100644 TA_API/storage/framework/cache/data/.gitignore create mode 100644 TA_API/storage/framework/sessions/.gitignore create mode 100644 TA_API/storage/framework/testing/.gitignore create mode 100644 TA_API/storage/framework/views/.gitignore create mode 100644 TA_API/storage/logs/.gitignore create mode 100644 TA_API/test-access.php create mode 100644 TA_API/tests/Feature/ExampleTest.php create mode 100644 TA_API/tests/TestCase.php create mode 100644 TA_API/tests/Unit/ExampleTest.php create mode 100644 TA_API/vite.config.js create mode 100644 TA_android/.env create mode 100644 TA_android/.gitignore create mode 100644 TA_android/.metadata create mode 100644 TA_android/.vscode/settings.json create mode 100644 TA_android/README.md create mode 100644 TA_android/analysis_options.yaml create mode 100644 TA_android/android/.gitignore create mode 100644 TA_android/android/app/build.gradle.kts create mode 100644 TA_android/android/app/src/debug/AndroidManifest.xml create mode 100644 TA_android/android/app/src/main/AndroidManifest.xml create mode 100644 TA_android/android/app/src/main/kotlin/com/example/tailorhub/MainActivity.kt create mode 100644 TA_android/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png create mode 100644 TA_android/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png create mode 100644 TA_android/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 TA_android/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png create mode 100644 TA_android/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png create mode 100644 TA_android/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png create mode 100644 TA_android/android/app/src/main/res/drawable/launch_background.xml create mode 100644 TA_android/android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml create mode 100644 TA_android/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 TA_android/android/app/src/main/res/mipmap-hdpi/launcher_icon.png create mode 100644 TA_android/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 TA_android/android/app/src/main/res/mipmap-mdpi/launcher_icon.png create mode 100644 TA_android/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 TA_android/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png create mode 100644 TA_android/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 TA_android/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png create mode 100644 TA_android/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 TA_android/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png create mode 100644 TA_android/android/app/src/main/res/values-night/styles.xml create mode 100644 TA_android/android/app/src/main/res/values/colors.xml create mode 100644 TA_android/android/app/src/main/res/values/styles.xml create mode 100644 TA_android/android/app/src/profile/AndroidManifest.xml create mode 100644 TA_android/android/build.gradle.kts create mode 100644 TA_android/android/gradle.properties create mode 100644 TA_android/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 TA_android/android/settings.gradle.kts create mode 100644 TA_android/assets/.env create mode 100644 TA_android/assets/images/LogoGelap.png create mode 100644 TA_android/assets/images/LogoPutih.png create mode 100644 TA_android/assets/images/avatar_default.png create mode 100644 TA_android/assets/images/model_jahit/celana.png create mode 100644 TA_android/assets/images/model_jahit/gamis.png create mode 100644 TA_android/assets/images/model_jahit/gaun.png create mode 100644 TA_android/assets/images/model_jahit/jasblezer.png create mode 100644 TA_android/assets/images/model_jahit/kebaya.png create mode 100644 TA_android/assets/images/model_jahit/kemeja.png create mode 100644 TA_android/assets/images/model_jahit/rok.png create mode 100644 TA_android/assets/images/model_jahit/seragam.png create mode 100644 TA_android/assets/images/no_location.png create mode 100644 TA_android/assets/images/payment/amex.png create mode 100644 TA_android/assets/images/payment/bca.png create mode 100644 TA_android/assets/images/payment/bni.png create mode 100644 TA_android/assets/images/payment/mandiri.png create mode 100644 TA_android/assets/images/payment/mastercard.png create mode 100644 TA_android/assets/images/payment/visa.png create mode 100644 TA_android/assets/images/payment_new/amex.png create mode 100644 TA_android/assets/images/payment_new/bca.png create mode 100644 TA_android/assets/images/payment_new/bni.png create mode 100644 TA_android/assets/images/payment_new/mandiri.png create mode 100644 TA_android/assets/images/payment_new/mastercard.png create mode 100644 TA_android/assets/images/payment_new/visa.png create mode 100644 TA_android/assets/images/tailor_1.png create mode 100644 TA_android/assets/images/tailor_2.png create mode 100644 TA_android/assets/images/tailor_3.png create mode 100644 TA_android/assets/images/tailor_4.png create mode 100644 TA_android/assets/images/tailor_5.png create mode 100644 TA_android/assets/images/tailor_6.png create mode 100644 TA_android/assets/images/tailor_banner.png create mode 100644 TA_android/assets/images/tailor_banner2.png create mode 100644 TA_android/assets/images/tailor_banner3.png create mode 100644 TA_android/assets/images/tailor_default.png create mode 100644 TA_android/ios/.gitignore create mode 100644 TA_android/ios/Flutter/AppFrameworkInfo.plist create mode 100644 TA_android/ios/Flutter/Debug.xcconfig create mode 100644 TA_android/ios/Flutter/Release.xcconfig create mode 100644 TA_android/ios/Runner.xcodeproj/project.pbxproj create mode 100644 TA_android/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 TA_android/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 TA_android/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 TA_android/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 TA_android/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 TA_android/ios/Runner/AppDelegate.swift create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 TA_android/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 TA_android/ios/Runner/Base.lproj/Main.storyboard create mode 100644 TA_android/ios/Runner/Info.plist create mode 100644 TA_android/ios/Runner/Runner-Bridging-Header.h create mode 100644 TA_android/ios/RunnerTests/RunnerTests.swift create mode 100644 TA_android/lib/core/controllers/auth_controller.dart create mode 100644 TA_android/lib/core/controllers/booking_controller.dart create mode 100644 TA_android/lib/core/controllers/category_controller.dart create mode 100644 TA_android/lib/core/controllers/gallery_controller.dart create mode 100644 TA_android/lib/core/controllers/midtrans_controller.dart create mode 100644 TA_android/lib/core/controllers/order_controller.dart create mode 100644 TA_android/lib/core/controllers/profile_controller.dart create mode 100644 TA_android/lib/core/controllers/wallet_wd_controller.dart create mode 100644 TA_android/lib/core/models/booking_model.dart create mode 100644 TA_android/lib/core/models/gallery_item_model.dart create mode 100644 TA_android/lib/core/models/gallery_model.dart create mode 100644 TA_android/lib/core/models/order_model.dart create mode 100644 TA_android/lib/core/models/review_model.dart create mode 100644 TA_android/lib/core/models/specialization_model.dart create mode 100644 TA_android/lib/core/models/tailor_model.dart create mode 100644 TA_android/lib/core/models/user_model.dart create mode 100644 TA_android/lib/core/models/wallet_model.dart create mode 100644 TA_android/lib/core/models/wallet_transaction_model.dart create mode 100644 TA_android/lib/core/models/withdrawals_model.dart create mode 100644 TA_android/lib/core/providers/user_provider.dart create mode 100644 TA_android/lib/core/routes/routes.dart create mode 100644 TA_android/lib/core/services/api_service.dart create mode 100644 TA_android/lib/core/services/auth_service.dart create mode 100644 TA_android/lib/core/services/booking_service.dart create mode 100644 TA_android/lib/core/services/forgot_passowrd_service.dart create mode 100644 TA_android/lib/core/services/midtrans_service.dart create mode 100644 TA_android/lib/core/services/midtrans_service.dart.bak create mode 100644 TA_android/lib/core/services/midtrans_service.dart.temp create mode 100644 TA_android/lib/core/services/profile_service.dart create mode 100644 TA_android/lib/core/services/search_service.dart create mode 100644 TA_android/lib/core/services/shared_prefs_helper.dart create mode 100644 TA_android/lib/core/services/wallet_wd_service.dart create mode 100644 TA_android/lib/core/theme/colors.dart create mode 100644 TA_android/lib/core/utils/app_routes.dart create mode 100644 TA_android/lib/core/utils/logger.dart create mode 100644 TA_android/lib/core/utils/url_helper.dart create mode 100644 TA_android/lib/core/widgets/category_card.dart create mode 100644 TA_android/lib/core/widgets/custom_button.dart create mode 100644 TA_android/lib/core/widgets/custom_text_field.dart create mode 100644 TA_android/lib/core/widgets/dropdown_field.dart create mode 100644 TA_android/lib/core/widgets/gallery_grid_widget.dart create mode 100644 TA_android/lib/core/widgets/image_upload_field.dart create mode 100644 TA_android/lib/core/widgets/label_text.dart create mode 100644 TA_android/lib/core/widgets/location_picker_dialog.dart create mode 100644 TA_android/lib/core/widgets/location_picker_map.dart create mode 100644 TA_android/lib/core/widgets/multiline_text_field.dart create mode 100644 TA_android/lib/core/widgets/password_field.dart create mode 100644 TA_android/lib/core/widgets/success_dialog.dart create mode 100644 TA_android/lib/core/widgets/tailor_card.dart create mode 100644 TA_android/lib/features/wallet/widgets/add_bank_account_form.dart create mode 100644 TA_android/lib/main.dart create mode 100644 TA_android/lib/pages/auth/forgot_password_customer_page.dart create mode 100644 TA_android/lib/pages/auth/forgot_password_page.dart create mode 100644 TA_android/lib/pages/auth/forgot_password_tailor_page.dart create mode 100644 TA_android/lib/pages/auth/login_page.dart create mode 100644 TA_android/lib/pages/auth/login_tailor_page.dart create mode 100644 TA_android/lib/pages/auth/register_customer_page.dart create mode 100644 TA_android/lib/pages/auth/register_tailor_page.dart create mode 100644 TA_android/lib/pages/clothing_category_page.dart create mode 100644 TA_android/lib/pages/costumer/home/booking_page.dart create mode 100644 TA_android/lib/pages/costumer/home/description_page.dart create mode 100644 TA_android/lib/pages/costumer/home/home_page.dart create mode 100644 TA_android/lib/pages/costumer/home/review_page.dart create mode 100644 TA_android/lib/pages/costumer/home/search_page.dart create mode 100644 TA_android/lib/pages/costumer/main_page.dart create mode 100644 TA_android/lib/pages/costumer/order/midtrans_webview_page.dart create mode 100644 TA_android/lib/pages/costumer/order/order_detail_page.dart create mode 100644 TA_android/lib/pages/costumer/order/order_page.dart create mode 100644 TA_android/lib/pages/costumer/order/payment_page.dart create mode 100644 TA_android/lib/pages/costumer/profile/profile_page.dart create mode 100644 TA_android/lib/pages/debug/debug_page.dart create mode 100644 TA_android/lib/pages/onboarding_page.dart create mode 100644 TA_android/lib/pages/register_option_page.dart create mode 100644 TA_android/lib/pages/splash_screen.dart create mode 100644 TA_android/lib/pages/tailor/home/home_page.dart create mode 100644 TA_android/lib/pages/tailor/main_page.dart create mode 100644 TA_android/lib/pages/tailor/order/order_detail_Page.dart create mode 100644 TA_android/lib/pages/tailor/order/order_page.dart create mode 100644 TA_android/lib/pages/tailor/order/temp_edit.dart create mode 100644 TA_android/lib/pages/tailor/order/temp_reject_booking.dart create mode 100644 TA_android/lib/pages/tailor/profile/profile_page.dart create mode 100644 TA_android/lib/pages/tailor/schedule/schedule_page.dart create mode 100644 TA_android/lib/pages/tailor/wallet/add_bank_account_page.dart create mode 100644 TA_android/lib/pages/tailor/wallet/wallet_history_page.dart create mode 100644 TA_android/lib/pages/tailor/wallet/withdrawal_page.dart create mode 100644 TA_android/linux/.gitignore create mode 100644 TA_android/linux/CMakeLists.txt create mode 100644 TA_android/linux/flutter/CMakeLists.txt create mode 100644 TA_android/linux/flutter/generated_plugin_registrant.cc create mode 100644 TA_android/linux/flutter/generated_plugin_registrant.h create mode 100644 TA_android/linux/flutter/generated_plugins.cmake create mode 100644 TA_android/linux/main.cc create mode 100644 TA_android/linux/my_application.cc create mode 100644 TA_android/linux/my_application.h create mode 100644 TA_android/linux/runner/CMakeLists.txt create mode 100644 TA_android/linux/runner/main.cc create mode 100644 TA_android/linux/runner/my_application.cc create mode 100644 TA_android/linux/runner/my_application.h create mode 100644 TA_android/macos/.gitignore create mode 100644 TA_android/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 TA_android/macos/Flutter/Flutter-Release.xcconfig create mode 100644 TA_android/macos/Flutter/GeneratedPluginRegistrant.swift create mode 100644 TA_android/macos/Runner.xcodeproj/project.pbxproj create mode 100644 TA_android/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 TA_android/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 TA_android/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 TA_android/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 TA_android/macos/Runner/AppDelegate.swift create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 TA_android/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 TA_android/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 TA_android/macos/Runner/Configs/Debug.xcconfig create mode 100644 TA_android/macos/Runner/Configs/Release.xcconfig create mode 100644 TA_android/macos/Runner/Configs/Warnings.xcconfig create mode 100644 TA_android/macos/Runner/DebugProfile.entitlements create mode 100644 TA_android/macos/Runner/Info.plist create mode 100644 TA_android/macos/Runner/MainFlutterWindow.swift create mode 100644 TA_android/macos/Runner/Release.entitlements create mode 100644 TA_android/macos/RunnerTests/RunnerTests.swift create mode 100644 TA_android/pubspec.lock create mode 100644 TA_android/pubspec.yaml create mode 100644 TA_android/temp_gallery_method.txt create mode 100644 TA_android/test/widget_test.dart create mode 100644 TA_android/web/favicon.png create mode 100644 TA_android/web/icons/Icon-192.png create mode 100644 TA_android/web/icons/Icon-512.png create mode 100644 TA_android/web/icons/Icon-maskable-192.png create mode 100644 TA_android/web/icons/Icon-maskable-512.png create mode 100644 TA_android/web/index.html create mode 100644 TA_android/web/manifest.json create mode 100644 TA_android/windows/.gitignore create mode 100644 TA_android/windows/CMakeLists.txt create mode 100644 TA_android/windows/flutter/CMakeLists.txt create mode 100644 TA_android/windows/flutter/generated_plugin_registrant.cc create mode 100644 TA_android/windows/flutter/generated_plugin_registrant.h create mode 100644 TA_android/windows/flutter/generated_plugins.cmake create mode 100644 TA_android/windows/runner/CMakeLists.txt create mode 100644 TA_android/windows/runner/Runner.rc create mode 100644 TA_android/windows/runner/flutter_window.cpp create mode 100644 TA_android/windows/runner/flutter_window.h create mode 100644 TA_android/windows/runner/main.cpp create mode 100644 TA_android/windows/runner/resource.h create mode 100644 TA_android/windows/runner/resources/app_icon.ico create mode 100644 TA_android/windows/runner/runner.exe.manifest create mode 100644 TA_android/windows/runner/utils.cpp create mode 100644 TA_android/windows/runner/utils.h create mode 100644 TA_android/windows/runner/win32_window.cpp create mode 100644 TA_android/windows/runner/win32_window.h create mode 100644 TA_website/.editorconfig create mode 100644 TA_website/.env.example create mode 100644 TA_website/.gitattributes create mode 100644 TA_website/.gitignore create mode 100644 TA_website/README.md create mode 100644 TA_website/_ide_helper.php create mode 100644 TA_website/_ide_helper_models.php create mode 100644 TA_website/app/Http/Controllers/Admin/AuthController.php create mode 100644 TA_website/app/Http/Controllers/Admin/BankAccountController.php create mode 100644 TA_website/app/Http/Controllers/Admin/BookingController.php create mode 100644 TA_website/app/Http/Controllers/Admin/CustomerController.php create mode 100644 TA_website/app/Http/Controllers/Admin/DashboardController.php create mode 100644 TA_website/app/Http/Controllers/Admin/LoginController.php create mode 100644 TA_website/app/Http/Controllers/Admin/SpecializationController.php create mode 100644 TA_website/app/Http/Controllers/Admin/TailorController.php create mode 100644 TA_website/app/Http/Controllers/Admin/WithdrawalController.php create mode 100644 TA_website/app/Http/Controllers/AdminController.php create mode 100644 TA_website/app/Http/Controllers/Controller.php create mode 100644 TA_website/app/Http/Middleware/AdminMiddleware.php create mode 100644 TA_website/app/Http/Middleware/Authenticate.php create mode 100644 TA_website/app/Http/Middleware/RedirectIfAuthenticated.php create mode 100644 TA_website/app/Models/Booking.php create mode 100644 TA_website/app/Models/Measurement.php create mode 100644 TA_website/app/Models/Order.php create mode 100644 TA_website/app/Models/Product.php create mode 100644 TA_website/app/Models/TailorGallery.php create mode 100644 TA_website/app/Models/TailorRating.php create mode 100644 TA_website/app/Models/User.php create mode 100644 TA_website/app/Providers/ApiServiceProvider.php create mode 100644 TA_website/app/Providers/AppServiceProvider.php create mode 100644 TA_website/app/Providers/RouteServiceProvider.php create mode 100644 TA_website/app/Services/ApiService.php create mode 100644 TA_website/artisan create mode 100644 TA_website/bootstrap/app.php create mode 100644 TA_website/bootstrap/cache/.gitignore create mode 100644 TA_website/bootstrap/providers.php create mode 100644 TA_website/composer.json create mode 100644 TA_website/composer.lock create mode 100644 TA_website/config/api.php create mode 100644 TA_website/config/app.php create mode 100644 TA_website/config/auth.php create mode 100644 TA_website/config/cache.php create mode 100644 TA_website/config/database.php create mode 100644 TA_website/config/filesystems.php create mode 100644 TA_website/config/logging.php create mode 100644 TA_website/config/mail.php create mode 100644 TA_website/config/queue.php create mode 100644 TA_website/config/services.php create mode 100644 TA_website/config/session.php create mode 100644 TA_website/database/.gitignore create mode 100644 TA_website/database/factories/UserFactory.php create mode 100644 TA_website/database/migrations/0001_01_01_000000_create_users_table.php create mode 100644 TA_website/database/migrations/0001_01_01_000001_create_cache_table.php create mode 100644 TA_website/database/migrations/0001_01_01_000002_create_jobs_table.php create mode 100644 TA_website/database/migrations/2025_05_07_000000_add_role_column_to_users_table.php create mode 100644 TA_website/database/schema/mysql-schema.sql create mode 100644 TA_website/database/seeders/DatabaseSeeder.php create mode 100644 TA_website/package.json create mode 100644 TA_website/phpunit.xml create mode 100644 TA_website/project_jahit (3).sql create mode 100644 TA_website/public/.htaccess create mode 100644 TA_website/public/favicon.ico create mode 100644 TA_website/public/image/LogoGelap.png create mode 100644 TA_website/public/image/LogoPutih.png create mode 100644 TA_website/public/index.php create mode 100644 TA_website/public/robots.txt create mode 100644 TA_website/resources/css/app.css create mode 100644 TA_website/resources/js/api.js create mode 100644 TA_website/resources/js/app.js create mode 100644 TA_website/resources/js/bootstrap.js create mode 100644 TA_website/resources/js/config.js create mode 100644 TA_website/resources/js/utils.js create mode 100644 TA_website/resources/views/admin/auth/login.blade.php create mode 100644 TA_website/resources/views/admin/bank-accounts/detail.blade.php create mode 100644 TA_website/resources/views/admin/bank-accounts/pending.blade.php create mode 100644 TA_website/resources/views/admin/bank-accounts/verified.blade.php create mode 100644 TA_website/resources/views/admin/bank-accounts/verify.blade.php create mode 100644 TA_website/resources/views/admin/bookings/index.blade.php create mode 100644 TA_website/resources/views/admin/customers/index.blade.php create mode 100644 TA_website/resources/views/admin/dashboard.blade.php create mode 100644 TA_website/resources/views/admin/js/config.blade.php create mode 100644 TA_website/resources/views/admin/layouts/admin.blade.php create mode 100644 TA_website/resources/views/admin/layouts/app.blade.php create mode 100644 TA_website/resources/views/admin/layouts/sidebar.blade.php create mode 100644 TA_website/resources/views/admin/specializations/index.blade.php create mode 100644 TA_website/resources/views/admin/tailors/index.blade.php create mode 100644 TA_website/resources/views/admin/user/admin.blade.php create mode 100644 TA_website/resources/views/admin/withdrawals/history.blade.php create mode 100644 TA_website/resources/views/admin/withdrawals/pending.blade.php create mode 100644 TA_website/resources/views/admin/withdrawals/process.blade.php create mode 100644 TA_website/resources/views/welcome.blade.php create mode 100644 TA_website/routes/console.php create mode 100644 TA_website/routes/web.php create mode 100644 TA_website/storage/app/.gitignore create mode 100644 TA_website/storage/app/private/.gitignore create mode 100644 TA_website/storage/app/public/.gitignore create mode 100644 TA_website/storage/framework/.gitignore create mode 100644 TA_website/storage/framework/cache/.gitignore create mode 100644 TA_website/storage/framework/cache/data/.gitignore create mode 100644 TA_website/storage/framework/sessions/.gitignore create mode 100644 TA_website/storage/framework/testing/.gitignore create mode 100644 TA_website/storage/framework/views/.gitignore create mode 100644 TA_website/storage/logs/.gitignore create mode 100644 TA_website/tests/Feature/ExampleTest.php create mode 100644 TA_website/tests/TestCase.php create mode 100644 TA_website/tests/Unit/ExampleTest.php create mode 100644 TA_website/vite.config.js diff --git a/TA_API/.editorconfig b/TA_API/.editorconfig new file mode 100644 index 0000000..8f0de65 --- /dev/null +++ b/TA_API/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[docker-compose.yml] +indent_size = 4 diff --git a/TA_API/.env.example b/TA_API/.env.example new file mode 100644 index 0000000..e35c519 --- /dev/null +++ b/TA_API/.env.example @@ -0,0 +1,70 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_STORE=database + +PHP_CLI_SERVER_WORKERS=4 + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=sqlite +# DB_HOST=127.0.0.1 +# DB_PORT=3306 +# DB_DATABASE=laravel +# DB_USERNAME=root +# DB_PASSWORD= + +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +# CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +VITE_APP_NAME="${APP_NAME}" + +MIDTRANS_CLIENT_KEY=SB-Mid-client-R_h8dtZUuy1pK8fn +MIDTRANS_SERVER_KEY=SB-Mid-server-yOklCwe5I_63lC5lDN3k8Kyw +MIDTRANS_IS_PRODUCTION=false +MIDTRANS_MERCHANT_ID=G937265596 diff --git a/TA_API/.gitattributes b/TA_API/.gitattributes new file mode 100644 index 0000000..fcb21d3 --- /dev/null +++ b/TA_API/.gitattributes @@ -0,0 +1,11 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/TA_API/.gitignore b/TA_API/.gitignore new file mode 100644 index 0000000..c7cf1fa --- /dev/null +++ b/TA_API/.gitignore @@ -0,0 +1,23 @@ +/.phpunit.cache +/node_modules +/public/build +/public/hot +/public/storage +/storage/*.key +/storage/pail +/vendor +.env +.env.backup +.env.production +.phpactor.json +.phpunit.result.cache +Homestead.json +Homestead.yaml +npm-debug.log +yarn-error.log +/auth.json +/.fleet +/.idea +/.nova +/.vscode +/.zed diff --git a/TA_API/.htaccess b/TA_API/.htaccess new file mode 100644 index 0000000..470d453 --- /dev/null +++ b/TA_API/.htaccess @@ -0,0 +1,14 @@ + + RewriteEngine On + + # Mengizinkan akses langsung ke storage + RewriteCond %{REQUEST_URI} ^/storage/(.*)$ + RewriteRule ^storage/(.*)$ public/storage/$1 [L,NC] + + # Redirect semua request ke public folder + RewriteRule ^(.*)$ public/$1 [L] + + + + Header set Access-Control-Allow-Origin "*" + \ No newline at end of file diff --git a/TA_API/EMAIL_VERIFICATION_DOC.md b/TA_API/EMAIL_VERIFICATION_DOC.md new file mode 100644 index 0000000..f5b1412 --- /dev/null +++ b/TA_API/EMAIL_VERIFICATION_DOC.md @@ -0,0 +1,172 @@ +# Dokumentasi API Verifikasi Email + +## Daftar Isi + +1. [Pengenalan](#pengenalan) +2. [Endpoint API Verifikasi Email](#endpoint-api-verifikasi-email) +3. [Pengujian di Postman](#pengujian-di-postman) +4. [Troubleshooting](#troubleshooting) + +## Pengenalan + +API Verifikasi Email digunakan untuk memverifikasi alamat email pengguna setelah registrasi. Sistem menggunakan link verifikasi yang dikirim ke email pengguna. Email verifikasi memiliki tampilan yang profesional dan berisi link yang dapat diklik untuk memverifikasi akun. + +## Endpoint API Verifikasi Email + +### 1. Kirim Email Verifikasi + +- **URL**: `/api/email/verification-notification` +- **Method**: `POST` +- **Headers**: + ``` + Accept: application/json + Content-Type: application/json + Authorization: Bearer {token} + ``` +- **Response Sukses** (200): + ```json + { + "success": true, + "data": { + "verification_url": "http://example.com/verify-email?expires=1234&id=1&signature=abcdef" + }, + "message": "Link verifikasi email telah dikirim." + } + ``` +- **Response Error** (400): + ```json + { + "success": false, + "message": "Email sudah terverifikasi." + } + ``` + +### 2. Verifikasi Email + +- **URL**: `/api/email/verify/{id}/{hash}` +- **Method**: `GET` +- **Headers**: + ``` + Accept: application/json + ``` +- **Response Sukses** (200): + ```json + { + "status": "success", + "message": "Email berhasil diverifikasi.", + "redirect_url": "http://example.com/login" + } + ``` +- **Response Error** (400): + ```json + { + "status": "error", + "message": "Invalid/Expired url provided.", + "redirect_url": "http://example.com/email-verification-error" + } + ``` + +### 3. Kirim Ulang Email Verifikasi + +- **URL**: `/api/email/verification-resend` +- **Method**: `POST` +- **Headers**: + ``` + Accept: application/json + Content-Type: application/json + Authorization: Bearer {token} + ``` +- **Response Sukses** (200): + ```json + { + "success": true, + "data": { + "verification_url": "http://example.com/verify-email?expires=1234&id=1&signature=abcdef" + }, + "message": "Link verifikasi email telah dikirim ulang." + } + ``` +- **Response Error** (400): + ```json + { + "success": false, + "message": "Email sudah terverifikasi." + } + ``` + +## Pengujian di Postman + +### Persiapan Collection + +1. Buka Postman dan buat collection baru bernama "Project Jahit API" +2. Tambahkan environment variable: + - `base_url`: `http://localhost:8000/api` + - `token`: (kosong, akan diisi setelah login) + +### Langkah-langkah Pengujian + +#### 1. Login untuk Mendapatkan Token + +1. **Request**: + - Method: `POST` + - URL: `{{base_url}}/pelanggan/login` atau `{{base_url}}/penjahit/login` + - Body (raw JSON): + ```json + { + "email": "email@example.com", + "password": "password" + } + ``` + +2. **Simpan Token**: + - Dari response, salin nilai token + - Simpan di environment variable `token` + +#### 2. Kirim Email Verifikasi + +1. **Request**: + - Method: `POST` + - URL: `{{base_url}}/email/verification-notification` + - Headers: + ``` + Authorization: Bearer {{token}} + Accept: application/json + ``` + +2. **Cek Email**: + - Buka email yang terdaftar + - Anda akan menerima email dengan tampilan profesional + - Email berisi tombol "Verifikasi Email Saya" + +#### 3. Verifikasi Email + +1. **Klik Link Verifikasi**: + - Klik tombol "Verifikasi Email Saya" di email + - Atau salin URL dari email dan buka di browser + +2. **Hasil**: + - Jika berhasil, Anda akan diarahkan ke halaman login + - Status akun Anda akan berubah menjadi terverifikasi + +## Troubleshooting + +### Masalah Umum: + +1. **"Email sudah terverifikasi"** + - Akun Anda sudah terverifikasi sebelumnya + - Tidak perlu melakukan verifikasi lagi + +2. **"Invalid/Expired url provided"** + - Link verifikasi sudah kadaluarsa (lebih dari 60 menit) + - Gunakan endpoint `/api/email/verification-resend` untuk mendapatkan link baru + +3. **"User not found"** + - ID pengguna dalam link tidak valid + - Pastikan menggunakan link terbaru + +### Tips: + +- Link verifikasi hanya berlaku selama 60 menit +- Jika link kadaluarsa, gunakan fitur "Kirim Ulang Email Verifikasi" +- Pastikan Anda login sebelum meminta link verifikasi baru +- Periksa folder spam jika email tidak muncul di inbox \ No newline at end of file diff --git a/TA_API/README.md b/TA_API/README.md new file mode 100644 index 0000000..9073331 --- /dev/null +++ b/TA_API/README.md @@ -0,0 +1,106 @@ +# Project Jahit API + +REST API untuk platform Project Jahit yang menghubungkan pelanggan dengan penjahit profesional. + +## Tentang Proyek + +Project Jahit adalah aplikasi yang memungkinkan pelanggan mencari penjahit terdekat, melakukan pemesanan jasa, dan melacak status pesanan. Penjahit dapat mengelola toko, layanan, galeri, dan booking. + +## Teknologi + +- Laravel 10 +- MySQL +- Laravel Sanctum (Autentikasi) + +## Fitur Utama + +- Registrasi dan login untuk pelanggan, penjahit, dan admin +- Pencarian penjahit berdasarkan spesialisasi +- Pemesanan jasa jahit +- Manajemen booking +- Pembayaran (mock) +- Rating dan ulasan +- Galeri hasil jahitan +- Manajemen layanan +- Dashboard untuk semua role + +## Instalasi + +```bash +# Clone repository +git clone https://github.com/username/project-jahit-api.git +cd project-jahit-api + +# Install dependencies +composer install + +# Salin file .env.example ke .env +cp .env.example .env + +# Generate application key +php artisan key:generate + +# Setup database di file .env +# DB_DATABASE=project_jahit +# DB_USERNAME=root +# DB_PASSWORD= + +# Migrasi dan seed database +php artisan migrate --seed + +# Buat symlink untuk storage +php artisan storage:link + +# Jalankan server development +php artisan serve +``` + +## Endpoints API + +API menyediakan berbagai endpoint untuk semua fitur. Dokumentasi lengkap dapat diakses melalui: + +``` +http://localhost:8000/docs +``` + +atau dengan membuka file `documentation.md` untuk format Markdown. + +## Struktur Folder + +- `app/Http/Controllers/Api` - API controllers +- `app/Models` - Model data aplikasi +- `database/migrations` - Migrasi database +- `routes/api.php` - Definisi route API +- `storage/app/public` - Storage untuk file yang diupload +- `resources/views/api-docs.blade.php` - Halaman dokumentasi API + +## Role Pengguna + +Aplikasi memiliki 3 role dengan hak akses berbeda: + +1. **Admin** - Mengelola seluruh data +2. **Penjahit** - Mengelola profil toko, layanan, dan booking +3. **Pelanggan** - Mencari penjahit, membuat booking, dan memberikan rating + +## Pengujian + +```bash +# Menjalankan unit test +php artisan test +``` + +## Akses File Media + +File yang diupload dapat diakses melalui URL: + +``` +http://localhost:8000/storage/{path} +``` + +Contoh: + +``` +http://localhost:8000/storage/design_photos/file.jpg +http://localhost:8000/storage/gallery_photos/photo.jpg +http://localhost:8000/storage/profile_photos/avatar.jpg +``` diff --git a/TA_API/RESET_PASSWORD_DOC.md b/TA_API/RESET_PASSWORD_DOC.md new file mode 100644 index 0000000..a141d89 --- /dev/null +++ b/TA_API/RESET_PASSWORD_DOC.md @@ -0,0 +1,207 @@ +# Dokumentasi Reset Password API + +## Daftar Isi + +1. [Pengenalan](#pengenalan) +2. [Endpoint Reset Password](#endpoint-reset-password) +3. [Pengujian di Postman](#pengujian-di-postman) +4. [Tampilan Email](#tampilan-email) +5. [Troubleshooting](#troubleshooting) + +## Pengenalan + +API Reset Password memungkinkan pengguna untuk mereset password mereka jika lupa. Sistem menggunakan PIN 6 digit yang dikirim ke email pengguna. Email reset password memiliki tampilan yang profesional dan berisi PIN yang dapat digunakan untuk mereset password. + +## Endpoint Reset Password + +### 1. Request Reset Password (Kirim PIN) + +- **URL**: + - Untuk pelanggan: `/api/pelanggan/forgot-password` + - Untuk penjahit: `/api/penjahit/forgot-password` +- **Method**: `POST` +- **Headers**: + ``` + Accept: application/json + Content-Type: application/json + ``` +- **Body**: + ```json + { + "email": "email@example.com" + } + ``` +- **Response Sukses** (200): + ```json + { + "success": true, + "data": { + "message": "PIN reset password telah dikirim ke email Anda" + }, + "message": "Kami sudah mengirim PIN reset password ke email Anda" + } + ``` +- **Response Error** (404): + ```json + { + "success": false, + "message": "Error.", + "data": { + "email": "Email tidak ditemukan" + } + } + ``` + +### 2. Reset Password (Gunakan PIN) + +- **URL**: + - Untuk pelanggan: `/api/pelanggan/reset-password` + - Untuk penjahit: `/api/penjahit/reset-password` +- **Method**: `POST` +- **Headers**: + ``` + Accept: application/json + Content-Type: application/json + ``` +- **Body**: + ```json + { + "email": "email@example.com", + "password": "password_baru", + "password_confirmation": "password_baru", + "pin": "123456" + } + ``` +- **Response Sukses** (200): + ```json + { + "success": true, + "data": [], + "message": "Password berhasil direset" + } + ``` +- **Response Error** (400): + ```json + { + "success": false, + "message": "Error.", + "data": { + "pin": "PIN tidak valid atau sudah kadaluarsa" + } + } + ``` + +## Pengujian di Postman + +### Persiapan Collection + +1. Buka Postman dan buat collection baru bernama "Project Jahit API" +2. Tambahkan environment variable: + - `base_url`: `http://localhost:8000/api` + - `email`: `email@example.com` (ganti dengan email yang terdaftar) + +### Langkah-langkah Pengujian + +#### 1. Meminta PIN Reset Password + +1. **Buat Request**: + - Method: `POST` + - URL: `{{base_url}}/pelanggan/forgot-password` (untuk pelanggan) atau `{{base_url}}/penjahit/forgot-password` (untuk penjahit) + - Headers: + ``` + Accept: application/json + Content-Type: application/json + ``` + - Body (raw JSON): + ```json + { + "email": "{{email}}" + } + ``` + +2. **Kirim Request**: + - Klik tombol "Send" + - Pastikan mendapat response sukses (200) + - Pesan sukses: "PIN reset password telah dikirim ke email Anda" + +3. **Cek Email**: + - Buka email yang terdaftar + - Anda akan menerima email dengan tampilan profesional + - Email berisi PIN 6 digit untuk reset password + - Catat PIN tersebut untuk langkah berikutnya + +#### 2. Reset Password dengan PIN + +1. **Buat Request**: + - Method: `POST` + - URL: `{{base_url}}/pelanggan/reset-password` (untuk pelanggan) atau `{{base_url}}/penjahit/reset-password` (untuk penjahit) + - Headers: + ``` + Accept: application/json + Content-Type: application/json + ``` + - Body (raw JSON): + ```json + { + "email": "{{email}}", + "password": "password_baru", + "password_confirmation": "password_baru", + "pin": "123456" // Ganti dengan PIN yang diterima di email + } + ``` + +2. **Kirim Request**: + - Klik tombol "Send" + - Pastikan mendapat response sukses (200) + - Pesan sukses: "Password berhasil direset" + +3. **Verifikasi Password Baru**: + - Coba login dengan password baru + - Pastikan bisa masuk ke sistem + +## Tampilan Email + +Email reset password memiliki tampilan profesional dengan: + +- Logo aplikasi di header +- Judul "Reset Password" +- Salam personal dengan nama pengguna +- PIN reset password dalam kotak yang menonjol +- Informasi keamanan dan masa berlaku PIN +- Footer dengan informasi kontak dan copyright + +Email dirancang untuk mudah dibaca di berbagai perangkat dan klien email. + +## Troubleshooting + +### Error Umum: + +1. **"Email tidak ditemukan"** + - Pastikan menggunakan email yang sudah terdaftar + - Pastikan menggunakan endpoint yang sesuai (pelanggan/penjahit) + - Cek penulisan email + +2. **"PIN tidak valid atau sudah kadaluarsa"** + - Pastikan menggunakan PIN terbaru dari email + - PIN hanya berlaku selama 60 menit + - PIN harus tepat 6 digit + +3. **"Error validasi"** + - Password minimal 8 karakter + - Password dan konfirmasi harus sama + - Email harus valid + +### Tips: + +- Selalu gunakan PIN terbaru dari email +- Jika PIN expired, ulangi proses dari awal +- Pastikan semua field terisi dengan benar +- Periksa folder spam jika email tidak muncul di inbox +- PIN hanya dapat digunakan satu kali + +### Kontak Support: + +Jika mengalami masalah, hubungi: + +- Email: support@projectjahit.com +- Telepon: (021) xxx-xxxx diff --git a/TA_API/_ide_helper.php b/TA_API/_ide_helper.php new file mode 100644 index 0000000..21843de --- /dev/null +++ b/TA_API/_ide_helper.php @@ -0,0 +1,27146 @@ + + * @see https://github.com/barryvdh/laravel-ide-helper + */ +namespace Illuminate\Support\Facades { + /** + * + * + * @see \Illuminate\Foundation\Application + */ + class App { + /** + * Begin configuring a new Laravel application instance. + * + * @param string|null $basePath + * @return \Illuminate\Foundation\Configuration\ApplicationBuilder + * @static + */ + public static function configure($basePath = null) + { + return \Illuminate\Foundation\Application::configure($basePath); + } + + /** + * Infer the application's base directory from the environment. + * + * @return string + * @static + */ + public static function inferBasePath() + { + return \Illuminate\Foundation\Application::inferBasePath(); + } + + /** + * Get the version number of the application. + * + * @return string + * @static + */ + public static function version() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->version(); + } + + /** + * Run the given array of bootstrap classes. + * + * @param string[] $bootstrappers + * @return void + * @static + */ + public static function bootstrapWith($bootstrappers) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bootstrapWith($bootstrappers); + } + + /** + * Register a callback to run after loading the environment. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function afterLoadingEnvironment($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterLoadingEnvironment($callback); + } + + /** + * Register a callback to run before a bootstrapper. + * + * @param string $bootstrapper + * @param \Closure $callback + * @return void + * @static + */ + public static function beforeBootstrapping($bootstrapper, $callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->beforeBootstrapping($bootstrapper, $callback); + } + + /** + * Register a callback to run after a bootstrapper. + * + * @param string $bootstrapper + * @param \Closure $callback + * @return void + * @static + */ + public static function afterBootstrapping($bootstrapper, $callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterBootstrapping($bootstrapper, $callback); + } + + /** + * Determine if the application has been bootstrapped before. + * + * @return bool + * @static + */ + public static function hasBeenBootstrapped() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->hasBeenBootstrapped(); + } + + /** + * Set the base path for the application. + * + * @param string $basePath + * @return \Illuminate\Foundation\Application + * @static + */ + public static function setBasePath($basePath) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->setBasePath($basePath); + } + + /** + * Get the path to the application "app" directory. + * + * @param string $path + * @return string + * @static + */ + public static function path($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->path($path); + } + + /** + * Set the application directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useAppPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useAppPath($path); + } + + /** + * Get the base path of the Laravel installation. + * + * @param string $path + * @return string + * @static + */ + public static function basePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->basePath($path); + } + + /** + * Get the path to the bootstrap directory. + * + * @param string $path + * @return string + * @static + */ + public static function bootstrapPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->bootstrapPath($path); + } + + /** + * Get the path to the service provider list in the bootstrap directory. + * + * @return string + * @static + */ + public static function getBootstrapProvidersPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getBootstrapProvidersPath(); + } + + /** + * Set the bootstrap file directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useBootstrapPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useBootstrapPath($path); + } + + /** + * Get the path to the application configuration files. + * + * @param string $path + * @return string + * @static + */ + public static function configPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->configPath($path); + } + + /** + * Set the configuration directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useConfigPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useConfigPath($path); + } + + /** + * Get the path to the database directory. + * + * @param string $path + * @return string + * @static + */ + public static function databasePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->databasePath($path); + } + + /** + * Set the database directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useDatabasePath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useDatabasePath($path); + } + + /** + * Get the path to the language files. + * + * @param string $path + * @return string + * @static + */ + public static function langPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->langPath($path); + } + + /** + * Set the language file directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useLangPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useLangPath($path); + } + + /** + * Get the path to the public / web directory. + * + * @param string $path + * @return string + * @static + */ + public static function publicPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->publicPath($path); + } + + /** + * Set the public / web directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function usePublicPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->usePublicPath($path); + } + + /** + * Get the path to the storage directory. + * + * @param string $path + * @return string + * @static + */ + public static function storagePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->storagePath($path); + } + + /** + * Set the storage directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useStoragePath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useStoragePath($path); + } + + /** + * Get the path to the resources directory. + * + * @param string $path + * @return string + * @static + */ + public static function resourcePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resourcePath($path); + } + + /** + * Get the path to the views directory. + * + * This method returns the first configured path in the array of view paths. + * + * @param string $path + * @return string + * @static + */ + public static function viewPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->viewPath($path); + } + + /** + * Join the given paths together. + * + * @param string $basePath + * @param string $path + * @return string + * @static + */ + public static function joinPaths($basePath, $path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->joinPaths($basePath, $path); + } + + /** + * Get the path to the environment file directory. + * + * @return string + * @static + */ + public static function environmentPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environmentPath(); + } + + /** + * Set the directory for the environment file. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useEnvironmentPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useEnvironmentPath($path); + } + + /** + * Set the environment file to be loaded during bootstrapping. + * + * @param string $file + * @return \Illuminate\Foundation\Application + * @static + */ + public static function loadEnvironmentFrom($file) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->loadEnvironmentFrom($file); + } + + /** + * Get the environment file the application is using. + * + * @return string + * @static + */ + public static function environmentFile() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environmentFile(); + } + + /** + * Get the fully qualified path to the environment file. + * + * @return string + * @static + */ + public static function environmentFilePath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environmentFilePath(); + } + + /** + * Get or check the current application environment. + * + * @param string|array $environments + * @return string|bool + * @static + */ + public static function environment(...$environments) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environment(...$environments); + } + + /** + * Determine if the application is in the local environment. + * + * @return bool + * @static + */ + public static function isLocal() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isLocal(); + } + + /** + * Determine if the application is in the production environment. + * + * @return bool + * @static + */ + public static function isProduction() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isProduction(); + } + + /** + * Detect the application's current environment. + * + * @param \Closure $callback + * @return string + * @static + */ + public static function detectEnvironment($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->detectEnvironment($callback); + } + + /** + * Determine if the application is running in the console. + * + * @return bool + * @static + */ + public static function runningInConsole() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->runningInConsole(); + } + + /** + * Determine if the application is running any of the given console commands. + * + * @param string|array $commands + * @return bool + * @static + */ + public static function runningConsoleCommand(...$commands) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->runningConsoleCommand(...$commands); + } + + /** + * Determine if the application is running unit tests. + * + * @return bool + * @static + */ + public static function runningUnitTests() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->runningUnitTests(); + } + + /** + * Determine if the application is running with debug mode enabled. + * + * @return bool + * @static + */ + public static function hasDebugModeEnabled() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->hasDebugModeEnabled(); + } + + /** + * Register a new registered listener. + * + * @param callable $callback + * @return void + * @static + */ + public static function registered($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registered($callback); + } + + /** + * Register all of the configured providers. + * + * @return void + * @static + */ + public static function registerConfiguredProviders() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registerConfiguredProviders(); + } + + /** + * Register a service provider with the application. + * + * @param \Illuminate\Support\ServiceProvider|string $provider + * @param bool $force + * @return \Illuminate\Support\ServiceProvider + * @static + */ + public static function register($provider, $force = false) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->register($provider, $force); + } + + /** + * Get the registered service provider instance if it exists. + * + * @param \Illuminate\Support\ServiceProvider|string $provider + * @return \Illuminate\Support\ServiceProvider|null + * @static + */ + public static function getProvider($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getProvider($provider); + } + + /** + * Get the registered service provider instances if any exist. + * + * @param \Illuminate\Support\ServiceProvider|string $provider + * @return array + * @static + */ + public static function getProviders($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getProviders($provider); + } + + /** + * Resolve a service provider instance from the class name. + * + * @param string $provider + * @return \Illuminate\Support\ServiceProvider + * @static + */ + public static function resolveProvider($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resolveProvider($provider); + } + + /** + * Load and boot all of the remaining deferred providers. + * + * @return void + * @static + */ + public static function loadDeferredProviders() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->loadDeferredProviders(); + } + + /** + * Load the provider for a deferred service. + * + * @param string $service + * @return void + * @static + */ + public static function loadDeferredProvider($service) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->loadDeferredProvider($service); + } + + /** + * Register a deferred provider and service. + * + * @param string $provider + * @param string|null $service + * @return void + * @static + */ + public static function registerDeferredProvider($provider, $service = null) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registerDeferredProvider($provider, $service); + } + + /** + * Resolve the given type from the container. + * + * @template TClass of object + * @param string|class-string $abstract + * @param array $parameters + * @return ($abstract is class-string ? TClass : mixed) + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @static + */ + public static function make($abstract, $parameters = []) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->make($abstract, $parameters); + } + + /** + * Determine if the given abstract type has been bound. + * + * @param string $abstract + * @return bool + * @static + */ + public static function bound($abstract) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->bound($abstract); + } + + /** + * Determine if the application has booted. + * + * @return bool + * @static + */ + public static function isBooted() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isBooted(); + } + + /** + * Boot the application's service providers. + * + * @return void + * @static + */ + public static function boot() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->boot(); + } + + /** + * Register a new boot listener. + * + * @param callable $callback + * @return void + * @static + */ + public static function booting($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->booting($callback); + } + + /** + * Register a new "booted" listener. + * + * @param callable $callback + * @return void + * @static + */ + public static function booted($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->booted($callback); + } + + /** + * {@inheritdoc} + * + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function handle($request, $type = 1, $catch = true) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->handle($request, $type, $catch); + } + + /** + * Handle the incoming HTTP request and send the response to the browser. + * + * @param \Illuminate\Http\Request $request + * @return void + * @static + */ + public static function handleRequest($request) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->handleRequest($request); + } + + /** + * Handle the incoming Artisan command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @return int + * @static + */ + public static function handleCommand($input) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->handleCommand($input); + } + + /** + * Determine if the framework's base configuration should be merged. + * + * @return bool + * @static + */ + public static function shouldMergeFrameworkConfiguration() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->shouldMergeFrameworkConfiguration(); + } + + /** + * Indicate that the framework's base configuration should not be merged. + * + * @return \Illuminate\Foundation\Application + * @static + */ + public static function dontMergeFrameworkConfiguration() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->dontMergeFrameworkConfiguration(); + } + + /** + * Determine if middleware has been disabled for the application. + * + * @return bool + * @static + */ + public static function shouldSkipMiddleware() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->shouldSkipMiddleware(); + } + + /** + * Get the path to the cached services.php file. + * + * @return string + * @static + */ + public static function getCachedServicesPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedServicesPath(); + } + + /** + * Get the path to the cached packages.php file. + * + * @return string + * @static + */ + public static function getCachedPackagesPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedPackagesPath(); + } + + /** + * Determine if the application configuration is cached. + * + * @return bool + * @static + */ + public static function configurationIsCached() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->configurationIsCached(); + } + + /** + * Get the path to the configuration cache file. + * + * @return string + * @static + */ + public static function getCachedConfigPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedConfigPath(); + } + + /** + * Determine if the application routes are cached. + * + * @return bool + * @static + */ + public static function routesAreCached() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->routesAreCached(); + } + + /** + * Get the path to the routes cache file. + * + * @return string + * @static + */ + public static function getCachedRoutesPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedRoutesPath(); + } + + /** + * Determine if the application events are cached. + * + * @return bool + * @static + */ + public static function eventsAreCached() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->eventsAreCached(); + } + + /** + * Get the path to the events cache file. + * + * @return string + * @static + */ + public static function getCachedEventsPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedEventsPath(); + } + + /** + * Add new prefix to list of absolute path prefixes. + * + * @param string $prefix + * @return \Illuminate\Foundation\Application + * @static + */ + public static function addAbsoluteCachePathPrefix($prefix) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->addAbsoluteCachePathPrefix($prefix); + } + + /** + * Get an instance of the maintenance mode manager implementation. + * + * @return \Illuminate\Contracts\Foundation\MaintenanceMode + * @static + */ + public static function maintenanceMode() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->maintenanceMode(); + } + + /** + * Determine if the application is currently down for maintenance. + * + * @return bool + * @static + */ + public static function isDownForMaintenance() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isDownForMaintenance(); + } + + /** + * Throw an HttpException with the given data. + * + * @param int $code + * @param string $message + * @param array $headers + * @return never + * @throws \Symfony\Component\HttpKernel\Exception\HttpException + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @static + */ + public static function abort($code, $message = '', $headers = []) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->abort($code, $message, $headers); + } + + /** + * Register a terminating callback with the application. + * + * @param callable|string $callback + * @return \Illuminate\Foundation\Application + * @static + */ + public static function terminating($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->terminating($callback); + } + + /** + * Terminate the application. + * + * @return void + * @static + */ + public static function terminate() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->terminate(); + } + + /** + * Get the service providers that have been loaded. + * + * @return array + * @static + */ + public static function getLoadedProviders() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getLoadedProviders(); + } + + /** + * Determine if the given service provider is loaded. + * + * @param string $provider + * @return bool + * @static + */ + public static function providerIsLoaded($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->providerIsLoaded($provider); + } + + /** + * Get the application's deferred services. + * + * @return array + * @static + */ + public static function getDeferredServices() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getDeferredServices(); + } + + /** + * Set the application's deferred services. + * + * @param array $services + * @return void + * @static + */ + public static function setDeferredServices($services) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->setDeferredServices($services); + } + + /** + * Determine if the given service is a deferred service. + * + * @param string $service + * @return bool + * @static + */ + public static function isDeferredService($service) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isDeferredService($service); + } + + /** + * Add an array of services to the application's deferred services. + * + * @param array $services + * @return void + * @static + */ + public static function addDeferredServices($services) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->addDeferredServices($services); + } + + /** + * Remove an array of services from the application's deferred services. + * + * @param array $services + * @return void + * @static + */ + public static function removeDeferredServices($services) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->removeDeferredServices($services); + } + + /** + * Configure the real-time facade namespace. + * + * @param string $namespace + * @return void + * @static + */ + public static function provideFacades($namespace) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->provideFacades($namespace); + } + + /** + * Get the current application locale. + * + * @return string + * @static + */ + public static function getLocale() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getLocale(); + } + + /** + * Get the current application locale. + * + * @return string + * @static + */ + public static function currentLocale() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->currentLocale(); + } + + /** + * Get the current application fallback locale. + * + * @return string + * @static + */ + public static function getFallbackLocale() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getFallbackLocale(); + } + + /** + * Set the current application locale. + * + * @param string $locale + * @return void + * @static + */ + public static function setLocale($locale) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->setLocale($locale); + } + + /** + * Set the current application fallback locale. + * + * @param string $fallbackLocale + * @return void + * @static + */ + public static function setFallbackLocale($fallbackLocale) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->setFallbackLocale($fallbackLocale); + } + + /** + * Determine if the application locale is the given locale. + * + * @param string $locale + * @return bool + * @static + */ + public static function isLocale($locale) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isLocale($locale); + } + + /** + * Register the core class aliases in the container. + * + * @return void + * @static + */ + public static function registerCoreContainerAliases() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registerCoreContainerAliases(); + } + + /** + * Flush the container of all bindings and resolved instances. + * + * @return void + * @static + */ + public static function flush() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->flush(); + } + + /** + * Get the application namespace. + * + * @return string + * @throws \RuntimeException + * @static + */ + public static function getNamespace() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getNamespace(); + } + + /** + * Define a contextual binding. + * + * @param array|string $concrete + * @return \Illuminate\Contracts\Container\ContextualBindingBuilder + * @static + */ + public static function when($concrete) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->when($concrete); + } + + /** + * Define a contextual binding based on an attribute. + * + * @param string $attribute + * @param \Closure $handler + * @return void + * @static + */ + public static function whenHasAttribute($attribute, $handler) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->whenHasAttribute($attribute, $handler); + } + + /** + * Returns true if the container can return an entry for the given identifier. + * + * Returns false otherwise. + * + * `has($id)` returning true does not mean that `get($id)` will not throw an exception. + * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`. + * + * @return bool + * @param string $id Identifier of the entry to look for. + * @return bool + * @static + */ + public static function has($id) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->has($id); + } + + /** + * Determine if the given abstract type has been resolved. + * + * @param string $abstract + * @return bool + * @static + */ + public static function resolved($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resolved($abstract); + } + + /** + * Determine if a given type is shared. + * + * @param string $abstract + * @return bool + * @static + */ + public static function isShared($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isShared($abstract); + } + + /** + * Determine if a given string is an alias. + * + * @param string $name + * @return bool + * @static + */ + public static function isAlias($name) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isAlias($name); + } + + /** + * Register a binding with the container. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + * @throws \TypeError + * @throws ReflectionException + * @static + */ + public static function bind($abstract, $concrete = null, $shared = false) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bind($abstract, $concrete, $shared); + } + + /** + * Determine if the container has a method binding. + * + * @param string $method + * @return bool + * @static + */ + public static function hasMethodBinding($method) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->hasMethodBinding($method); + } + + /** + * Bind a callback to resolve with Container::call. + * + * @param array|string $method + * @param \Closure $callback + * @return void + * @static + */ + public static function bindMethod($method, $callback) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bindMethod($method, $callback); + } + + /** + * Get the method binding for the given method. + * + * @param string $method + * @param mixed $instance + * @return mixed + * @static + */ + public static function callMethodBinding($method, $instance) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->callMethodBinding($method, $instance); + } + + /** + * Add a contextual binding to the container. + * + * @param string $concrete + * @param \Closure|string $abstract + * @param \Closure|string $implementation + * @return void + * @static + */ + public static function addContextualBinding($concrete, $abstract, $implementation) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->addContextualBinding($concrete, $abstract, $implementation); + } + + /** + * Register a binding if it hasn't already been registered. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + * @static + */ + public static function bindIf($abstract, $concrete = null, $shared = false) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bindIf($abstract, $concrete, $shared); + } + + /** + * Register a shared binding in the container. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function singleton($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->singleton($abstract, $concrete); + } + + /** + * Register a shared binding if it hasn't already been registered. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function singletonIf($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->singletonIf($abstract, $concrete); + } + + /** + * Register a scoped binding in the container. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function scoped($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->scoped($abstract, $concrete); + } + + /** + * Register a scoped binding if it hasn't already been registered. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function scopedIf($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->scopedIf($abstract, $concrete); + } + + /** + * "Extend" an abstract type in the container. + * + * @param string $abstract + * @param \Closure $closure + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function extend($abstract, $closure) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->extend($abstract, $closure); + } + + /** + * Register an existing instance as shared in the container. + * + * @template TInstance of mixed + * @param string $abstract + * @param TInstance $instance + * @return TInstance + * @static + */ + public static function instance($abstract, $instance) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->instance($abstract, $instance); + } + + /** + * Assign a set of tags to a given binding. + * + * @param array|string $abstracts + * @param array|mixed $tags + * @return void + * @static + */ + public static function tag($abstracts, $tags) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->tag($abstracts, $tags); + } + + /** + * Resolve all of the bindings for a given tag. + * + * @param string $tag + * @return iterable + * @static + */ + public static function tagged($tag) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->tagged($tag); + } + + /** + * Alias a type to a different name. + * + * @param string $abstract + * @param string $alias + * @return void + * @throws \LogicException + * @static + */ + public static function alias($abstract, $alias) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->alias($abstract, $alias); + } + + /** + * Bind a new callback to an abstract's rebind event. + * + * @param string $abstract + * @param \Closure $callback + * @return mixed + * @static + */ + public static function rebinding($abstract, $callback) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->rebinding($abstract, $callback); + } + + /** + * Refresh an instance on the given target and method. + * + * @param string $abstract + * @param mixed $target + * @param string $method + * @return mixed + * @static + */ + public static function refresh($abstract, $target, $method) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->refresh($abstract, $target, $method); + } + + /** + * Wrap the given closure such that its dependencies will be injected when executed. + * + * @param \Closure $callback + * @param array $parameters + * @return \Closure + * @static + */ + public static function wrap($callback, $parameters = []) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->wrap($callback, $parameters); + } + + /** + * Call the given Closure / class@method and inject its dependencies. + * + * @param callable|string $callback + * @param array $parameters + * @param string|null $defaultMethod + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function call($callback, $parameters = [], $defaultMethod = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->call($callback, $parameters, $defaultMethod); + } + + /** + * Get a closure to resolve the given type from the container. + * + * @template TClass of object + * @param string|class-string $abstract + * @return ($abstract is class-string ? \Closure(): TClass : \Closure(): mixed) + * @static + */ + public static function factory($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->factory($abstract); + } + + /** + * An alias function name for make(). + * + * @template TClass of object + * @param string|class-string|callable $abstract + * @param array $parameters + * @return ($abstract is class-string ? TClass : mixed) + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @static + */ + public static function makeWith($abstract, $parameters = []) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->makeWith($abstract, $parameters); + } + + /** + * {@inheritdoc} + * + * @template TClass of object + * @param string|class-string $id + * @return ($id is class-string ? TClass : mixed) + * @static + */ + public static function get($id) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->get($id); + } + + /** + * Instantiate a concrete instance of the given type. + * + * @template TClass of object + * @param \Closure(static, array): TClass|class-string $concrete + * @return TClass + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @throws \Illuminate\Contracts\Container\CircularDependencyException + * @static + */ + public static function build($concrete) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->build($concrete); + } + + /** + * Resolve a dependency based on an attribute. + * + * @param \ReflectionAttribute $attribute + * @return mixed + * @static + */ + public static function resolveFromAttribute($attribute) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resolveFromAttribute($attribute); + } + + /** + * Register a new before resolving callback for all types. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + * @static + */ + public static function beforeResolving($abstract, $callback = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->beforeResolving($abstract, $callback); + } + + /** + * Register a new resolving callback. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + * @static + */ + public static function resolving($abstract, $callback = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->resolving($abstract, $callback); + } + + /** + * Register a new after resolving callback for all types. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + * @static + */ + public static function afterResolving($abstract, $callback = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterResolving($abstract, $callback); + } + + /** + * Register a new after resolving attribute callback for all types. + * + * @param string $attribute + * @param \Closure $callback + * @return void + * @static + */ + public static function afterResolvingAttribute($attribute, $callback) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterResolvingAttribute($attribute, $callback); + } + + /** + * Fire all of the after resolving attribute callbacks. + * + * @param \ReflectionAttribute[] $attributes + * @param mixed $object + * @return void + * @static + */ + public static function fireAfterResolvingAttributeCallbacks($attributes, $object) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->fireAfterResolvingAttributeCallbacks($attributes, $object); + } + + /** + * Get the container's bindings. + * + * @return array + * @static + */ + public static function getBindings() + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getBindings(); + } + + /** + * Get the alias for an abstract if available. + * + * @param string $abstract + * @return string + * @static + */ + public static function getAlias($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getAlias($abstract); + } + + /** + * Remove all of the extender callbacks for a given type. + * + * @param string $abstract + * @return void + * @static + */ + public static function forgetExtenders($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetExtenders($abstract); + } + + /** + * Remove a resolved instance from the instance cache. + * + * @param string $abstract + * @return void + * @static + */ + public static function forgetInstance($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetInstance($abstract); + } + + /** + * Clear all of the instances from the container. + * + * @return void + * @static + */ + public static function forgetInstances() + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetInstances(); + } + + /** + * Clear all of the scoped instances from the container. + * + * @return void + * @static + */ + public static function forgetScopedInstances() + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetScopedInstances(); + } + + /** + * Get the globally available instance of the container. + * + * @return static + * @static + */ + public static function getInstance() + { + //Method inherited from \Illuminate\Container\Container + return \Illuminate\Foundation\Application::getInstance(); + } + + /** + * Set the shared instance of the container. + * + * @param \Illuminate\Contracts\Container\Container|null $container + * @return \Illuminate\Contracts\Container\Container|static + * @static + */ + public static function setInstance($container = null) + { + //Method inherited from \Illuminate\Container\Container + return \Illuminate\Foundation\Application::setInstance($container); + } + + /** + * Determine if a given offset exists. + * + * @param string $key + * @return bool + * @static + */ + public static function offsetExists($key) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->offsetExists($key); + } + + /** + * Get the value at a given offset. + * + * @param string $key + * @return mixed + * @static + */ + public static function offsetGet($key) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->offsetGet($key); + } + + /** + * Set the value at a given offset. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($key, $value) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->offsetSet($key, $value); + } + + /** + * Unset the value at a given offset. + * + * @param string $key + * @return void + * @static + */ + public static function offsetUnset($key) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->offsetUnset($key); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Foundation\Application::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Foundation\Application::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Foundation\Application::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Foundation\Application::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Foundation\Console\Kernel + */ + class Artisan { + /** + * Re-route the Symfony command events to their Laravel counterparts. + * + * @internal + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function rerouteSymfonyCommandEvents() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->rerouteSymfonyCommandEvents(); + } + + /** + * Run the console application. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface|null $output + * @return int + * @static + */ + public static function handle($input, $output = null) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->handle($input, $output); + } + + /** + * Terminate the application. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param int $status + * @return void + * @static + */ + public static function terminate($input, $status) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->terminate($input, $status); + } + + /** + * Register a callback to be invoked when the command lifecycle duration exceeds a given amount of time. + * + * @param \DateTimeInterface|\Carbon\CarbonInterval|float|int $threshold + * @param callable $handler + * @return void + * @static + */ + public static function whenCommandLifecycleIsLongerThan($threshold, $handler) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->whenCommandLifecycleIsLongerThan($threshold, $handler); + } + + /** + * When the command being handled started. + * + * @return \Illuminate\Support\Carbon|null + * @static + */ + public static function commandStartedAt() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->commandStartedAt(); + } + + /** + * Resolve a console schedule instance. + * + * @return \Illuminate\Console\Scheduling\Schedule + * @static + */ + public static function resolveConsoleSchedule() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->resolveConsoleSchedule(); + } + + /** + * Register a Closure based command with the application. + * + * @param string $signature + * @param \Closure $callback + * @return \Illuminate\Foundation\Console\ClosureCommand + * @static + */ + public static function command($signature, $callback) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->command($signature, $callback); + } + + /** + * Register the given command with the console application. + * + * @param \Symfony\Component\Console\Command\Command $command + * @return void + * @static + */ + public static function registerCommand($command) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->registerCommand($command); + } + + /** + * Run an Artisan console command by name. + * + * @param string $command + * @param array $parameters + * @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer + * @return int + * @throws \Symfony\Component\Console\Exception\CommandNotFoundException + * @static + */ + public static function call($command, $parameters = [], $outputBuffer = null) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->call($command, $parameters, $outputBuffer); + } + + /** + * Queue the given console command. + * + * @param string $command + * @param array $parameters + * @return \Illuminate\Foundation\Bus\PendingDispatch + * @static + */ + public static function queue($command, $parameters = []) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->queue($command, $parameters); + } + + /** + * Get all of the commands registered with the console. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->all(); + } + + /** + * Get the output for the last run command. + * + * @return string + * @static + */ + public static function output() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->output(); + } + + /** + * Bootstrap the application for artisan commands. + * + * @return void + * @static + */ + public static function bootstrap() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->bootstrap(); + } + + /** + * Bootstrap the application without booting service providers. + * + * @return void + * @static + */ + public static function bootstrapWithoutBootingProviders() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->bootstrapWithoutBootingProviders(); + } + + /** + * Set the Artisan application instance. + * + * @param \Illuminate\Console\Application|null $artisan + * @return void + * @static + */ + public static function setArtisan($artisan) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->setArtisan($artisan); + } + + /** + * Set the Artisan commands provided by the application. + * + * @param array $commands + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function addCommands($commands) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->addCommands($commands); + } + + /** + * Set the paths that should have their Artisan commands automatically discovered. + * + * @param array $paths + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function addCommandPaths($paths) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->addCommandPaths($paths); + } + + /** + * Set the paths that should have their Artisan "routes" automatically discovered. + * + * @param array $paths + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function addCommandRoutePaths($paths) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->addCommandRoutePaths($paths); + } + + } + /** + * + * + * @see \Illuminate\Auth\AuthManager + * @see \Illuminate\Auth\SessionGuard + */ + class Auth { + /** + * Attempt to get the guard from the local cache. + * + * @param string|null $name + * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard + * @static + */ + public static function guard($name = null) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->guard($name); + } + + /** + * Create a session based authentication guard. + * + * @param string $name + * @param array $config + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function createSessionDriver($name, $config) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->createSessionDriver($name, $config); + } + + /** + * Create a token based authentication guard. + * + * @param string $name + * @param array $config + * @return \Illuminate\Auth\TokenGuard + * @static + */ + public static function createTokenDriver($name, $config) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->createTokenDriver($name, $config); + } + + /** + * Get the default authentication driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default guard driver the factory should serve. + * + * @param string $name + * @return void + * @static + */ + public static function shouldUse($name) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + $instance->shouldUse($name); + } + + /** + * Set the default authentication driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Register a new callback based request guard. + * + * @param string $driver + * @param callable $callback + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function viaRequest($driver, $callback) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->viaRequest($driver, $callback); + } + + /** + * Get the user resolver callback. + * + * @return \Closure + * @static + */ + public static function userResolver() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->userResolver(); + } + + /** + * Set the callback to be used to resolve users. + * + * @param \Closure $userResolver + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function resolveUsersUsing($userResolver) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->resolveUsersUsing($userResolver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Register a custom provider creator Closure. + * + * @param string $name + * @param \Closure $callback + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function provider($name, $callback) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->provider($name, $callback); + } + + /** + * Determines if any guards have already been resolved. + * + * @return bool + * @static + */ + public static function hasResolvedGuards() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->hasResolvedGuards(); + } + + /** + * Forget all of the resolved guard instances. + * + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function forgetGuards() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->forgetGuards(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->setApplication($app); + } + + /** + * Create the user provider implementation for the driver. + * + * @param string|null $provider + * @return \Illuminate\Contracts\Auth\UserProvider|null + * @throws \InvalidArgumentException + * @static + */ + public static function createUserProvider($provider = null) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->createUserProvider($provider); + } + + /** + * Get the default user provider name. + * + * @return string + * @static + */ + public static function getDefaultUserProvider() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->getDefaultUserProvider(); + } + + /** + * Get the currently authenticated user. + * + * @return \App\Models\User|null + * @static + */ + public static function user() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->user(); + } + + /** + * Get the ID for the currently authenticated user. + * + * @return int|string|null + * @static + */ + public static function id() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->id(); + } + + /** + * Log a user into the application without sessions or cookies. + * + * @param array $credentials + * @return bool + * @static + */ + public static function once($credentials = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->once($credentials); + } + + /** + * Log the given user ID into the application without sessions or cookies. + * + * @param mixed $id + * @return \App\Models\User|false + * @static + */ + public static function onceUsingId($id) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->onceUsingId($id); + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + * @static + */ + public static function validate($credentials = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->validate($credentials); + } + + /** + * Attempt to authenticate using HTTP Basic Auth. + * + * @param string $field + * @param array $extraConditions + * @return \Symfony\Component\HttpFoundation\Response|null + * @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException + * @static + */ + public static function basic($field = 'email', $extraConditions = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->basic($field, $extraConditions); + } + + /** + * Perform a stateless HTTP Basic login attempt. + * + * @param string $field + * @param array $extraConditions + * @return \Symfony\Component\HttpFoundation\Response|null + * @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException + * @static + */ + public static function onceBasic($field = 'email', $extraConditions = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->onceBasic($field, $extraConditions); + } + + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * @param bool $remember + * @return bool + * @static + */ + public static function attempt($credentials = [], $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->attempt($credentials, $remember); + } + + /** + * Attempt to authenticate a user with credentials and additional callbacks. + * + * @param array $credentials + * @param array|callable|null $callbacks + * @param bool $remember + * @return bool + * @static + */ + public static function attemptWhen($credentials = [], $callbacks = null, $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->attemptWhen($credentials, $callbacks, $remember); + } + + /** + * Log the given user ID into the application. + * + * @param mixed $id + * @param bool $remember + * @return \App\Models\User|false + * @static + */ + public static function loginUsingId($id, $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->loginUsingId($id, $remember); + } + + /** + * Log a user into the application. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param bool $remember + * @return void + * @static + */ + public static function login($user, $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->login($user, $remember); + } + + /** + * Log the user out of the application. + * + * @return void + * @static + */ + public static function logout() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->logout(); + } + + /** + * Log the user out of the application on their current device only. + * + * This method does not cycle the "remember" token. + * + * @return void + * @static + */ + public static function logoutCurrentDevice() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->logoutCurrentDevice(); + } + + /** + * Invalidate other sessions for the current user. + * + * The application must be using the AuthenticateSession middleware. + * + * @param string $password + * @return \App\Models\User|null + * @throws \Illuminate\Auth\AuthenticationException + * @static + */ + public static function logoutOtherDevices($password) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->logoutOtherDevices($password); + } + + /** + * Register an authentication attempt event listener. + * + * @param mixed $callback + * @return void + * @static + */ + public static function attempting($callback) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->attempting($callback); + } + + /** + * Get the last user we attempted to authenticate. + * + * @return \App\Models\User + * @static + */ + public static function getLastAttempted() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getLastAttempted(); + } + + /** + * Get a unique identifier for the auth session value. + * + * @return string + * @static + */ + public static function getName() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getName(); + } + + /** + * Get the name of the cookie used to store the "recaller". + * + * @return string + * @static + */ + public static function getRecallerName() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getRecallerName(); + } + + /** + * Determine if the user was authenticated via "remember me" cookie. + * + * @return bool + * @static + */ + public static function viaRemember() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->viaRemember(); + } + + /** + * Set the number of minutes the remember me cookie should be valid for. + * + * @param int $minutes + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function setRememberDuration($minutes) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->setRememberDuration($minutes); + } + + /** + * Get the cookie creator instance used by the guard. + * + * @return \Illuminate\Contracts\Cookie\QueueingFactory + * @throws \RuntimeException + * @static + */ + public static function getCookieJar() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getCookieJar(); + } + + /** + * Set the cookie creator instance used by the guard. + * + * @param \Illuminate\Contracts\Cookie\QueueingFactory $cookie + * @return void + * @static + */ + public static function setCookieJar($cookie) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->setCookieJar($cookie); + } + + /** + * Get the event dispatcher instance. + * + * @return \Illuminate\Contracts\Events\Dispatcher + * @static + */ + public static function getDispatcher() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getDispatcher(); + } + + /** + * Set the event dispatcher instance. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + * @static + */ + public static function setDispatcher($events) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->setDispatcher($events); + } + + /** + * Get the session store used by the guard. + * + * @return \Illuminate\Contracts\Session\Session + * @static + */ + public static function getSession() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getSession(); + } + + /** + * Return the currently cached user. + * + * @return \App\Models\User|null + * @static + */ + public static function getUser() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getUser(); + } + + /** + * Set the current user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function setUser($user) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->setUser($user); + } + + /** + * Get the current request instance. + * + * @return \Symfony\Component\HttpFoundation\Request + * @static + */ + public static function getRequest() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getRequest(); + } + + /** + * Set the current request instance. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function setRequest($request) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->setRequest($request); + } + + /** + * Get the timebox instance used by the guard. + * + * @return \Illuminate\Support\Timebox + * @static + */ + public static function getTimebox() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getTimebox(); + } + + /** + * Determine if the current user is authenticated. If not, throw an exception. + * + * @return \App\Models\User + * @throws \Illuminate\Auth\AuthenticationException + * @static + */ + public static function authenticate() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->authenticate(); + } + + /** + * Determine if the guard has a user instance. + * + * @return bool + * @static + */ + public static function hasUser() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->hasUser(); + } + + /** + * Determine if the current user is authenticated. + * + * @return bool + * @static + */ + public static function check() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->check(); + } + + /** + * Determine if the current user is a guest. + * + * @return bool + * @static + */ + public static function guest() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->guest(); + } + + /** + * Forget the current user. + * + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function forgetUser() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->forgetUser(); + } + + /** + * Get the user provider used by the guard. + * + * @return \Illuminate\Contracts\Auth\UserProvider + * @static + */ + public static function getProvider() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getProvider(); + } + + /** + * Set the user provider used by the guard. + * + * @param \Illuminate\Contracts\Auth\UserProvider $provider + * @return void + * @static + */ + public static function setProvider($provider) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->setProvider($provider); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Auth\SessionGuard::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Auth\SessionGuard::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Auth\SessionGuard::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Auth\SessionGuard::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\View\Compilers\BladeCompiler + */ + class Blade { + /** + * Compile the view at the given path. + * + * @param string|null $path + * @return void + * @static + */ + public static function compile($path = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->compile($path); + } + + /** + * Get the path currently being compiled. + * + * @return string + * @static + */ + public static function getPath() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getPath(); + } + + /** + * Set the path currently being compiled. + * + * @param string $path + * @return void + * @static + */ + public static function setPath($path) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->setPath($path); + } + + /** + * Compile the given Blade template contents. + * + * @param string $value + * @return string + * @static + */ + public static function compileString($value) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileString($value); + } + + /** + * Evaluate and render a Blade string to HTML. + * + * @param string $string + * @param array $data + * @param bool $deleteCachedView + * @return string + * @static + */ + public static function render($string, $data = [], $deleteCachedView = false) + { + return \Illuminate\View\Compilers\BladeCompiler::render($string, $data, $deleteCachedView); + } + + /** + * Render a component instance to HTML. + * + * @param \Illuminate\View\Component $component + * @return string + * @static + */ + public static function renderComponent($component) + { + return \Illuminate\View\Compilers\BladeCompiler::renderComponent($component); + } + + /** + * Strip the parentheses from the given expression. + * + * @param string $expression + * @return string + * @static + */ + public static function stripParentheses($expression) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->stripParentheses($expression); + } + + /** + * Register a custom Blade compiler. + * + * @param callable $compiler + * @return void + * @static + */ + public static function extend($compiler) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->extend($compiler); + } + + /** + * Get the extensions used by the compiler. + * + * @return array + * @static + */ + public static function getExtensions() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getExtensions(); + } + + /** + * Register an "if" statement directive. + * + * @param string $name + * @param callable $callback + * @return void + * @static + */ + public static function if($name, $callback) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->if($name, $callback); + } + + /** + * Check the result of a condition. + * + * @param string $name + * @param mixed $parameters + * @return bool + * @static + */ + public static function check($name, ...$parameters) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->check($name, ...$parameters); + } + + /** + * Register a class-based component alias directive. + * + * @param string $class + * @param string|null $alias + * @param string $prefix + * @return void + * @static + */ + public static function component($class, $alias = null, $prefix = '') + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->component($class, $alias, $prefix); + } + + /** + * Register an array of class-based components. + * + * @param array $components + * @param string $prefix + * @return void + * @static + */ + public static function components($components, $prefix = '') + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->components($components, $prefix); + } + + /** + * Get the registered class component aliases. + * + * @return array + * @static + */ + public static function getClassComponentAliases() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getClassComponentAliases(); + } + + /** + * Register a new anonymous component path. + * + * @param string $path + * @param string|null $prefix + * @return void + * @static + */ + public static function anonymousComponentPath($path, $prefix = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->anonymousComponentPath($path, $prefix); + } + + /** + * Register an anonymous component namespace. + * + * @param string $directory + * @param string|null $prefix + * @return void + * @static + */ + public static function anonymousComponentNamespace($directory, $prefix = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->anonymousComponentNamespace($directory, $prefix); + } + + /** + * Register a class-based component namespace. + * + * @param string $namespace + * @param string $prefix + * @return void + * @static + */ + public static function componentNamespace($namespace, $prefix) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->componentNamespace($namespace, $prefix); + } + + /** + * Get the registered anonymous component paths. + * + * @return array + * @static + */ + public static function getAnonymousComponentPaths() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getAnonymousComponentPaths(); + } + + /** + * Get the registered anonymous component namespaces. + * + * @return array + * @static + */ + public static function getAnonymousComponentNamespaces() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getAnonymousComponentNamespaces(); + } + + /** + * Get the registered class component namespaces. + * + * @return array + * @static + */ + public static function getClassComponentNamespaces() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getClassComponentNamespaces(); + } + + /** + * Register a component alias directive. + * + * @param string $path + * @param string|null $alias + * @return void + * @static + */ + public static function aliasComponent($path, $alias = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->aliasComponent($path, $alias); + } + + /** + * Register an include alias directive. + * + * @param string $path + * @param string|null $alias + * @return void + * @static + */ + public static function include($path, $alias = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->include($path, $alias); + } + + /** + * Register an include alias directive. + * + * @param string $path + * @param string|null $alias + * @return void + * @static + */ + public static function aliasInclude($path, $alias = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->aliasInclude($path, $alias); + } + + /** + * Register a handler for custom directives, binding the handler to the compiler. + * + * @param string $name + * @param callable $handler + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function bindDirective($name, $handler) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->bindDirective($name, $handler); + } + + /** + * Register a handler for custom directives. + * + * @param string $name + * @param callable $handler + * @param bool $bind + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function directive($name, $handler, $bind = false) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->directive($name, $handler, $bind); + } + + /** + * Get the list of custom directives. + * + * @return array + * @static + */ + public static function getCustomDirectives() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getCustomDirectives(); + } + + /** + * Indicate that the following callable should be used to prepare strings for compilation. + * + * @param callable $callback + * @return \Illuminate\View\Compilers\BladeCompiler + * @static + */ + public static function prepareStringsForCompilationUsing($callback) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->prepareStringsForCompilationUsing($callback); + } + + /** + * Register a new precompiler. + * + * @param callable $precompiler + * @return void + * @static + */ + public static function precompiler($precompiler) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->precompiler($precompiler); + } + + /** + * Set the echo format to be used by the compiler. + * + * @param string $format + * @return void + * @static + */ + public static function setEchoFormat($format) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->setEchoFormat($format); + } + + /** + * Set the "echo" format to double encode entities. + * + * @return void + * @static + */ + public static function withDoubleEncoding() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->withDoubleEncoding(); + } + + /** + * Set the "echo" format to not double encode entities. + * + * @return void + * @static + */ + public static function withoutDoubleEncoding() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->withoutDoubleEncoding(); + } + + /** + * Indicate that component tags should not be compiled. + * + * @return void + * @static + */ + public static function withoutComponentTags() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->withoutComponentTags(); + } + + /** + * Get the path to the compiled version of a view. + * + * @param string $path + * @return string + * @static + */ + public static function getCompiledPath($path) + { + //Method inherited from \Illuminate\View\Compilers\Compiler + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getCompiledPath($path); + } + + /** + * Determine if the view at the given path is expired. + * + * @param string $path + * @return bool + * @throws \ErrorException + * @static + */ + public static function isExpired($path) + { + //Method inherited from \Illuminate\View\Compilers\Compiler + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->isExpired($path); + } + + /** + * Get a new component hash for a component name. + * + * @param string $component + * @return string + * @static + */ + public static function newComponentHash($component) + { + return \Illuminate\View\Compilers\BladeCompiler::newComponentHash($component); + } + + /** + * Compile a class component opening. + * + * @param string $component + * @param string $alias + * @param string $data + * @param string $hash + * @return string + * @static + */ + public static function compileClassComponentOpening($component, $alias, $data, $hash) + { + return \Illuminate\View\Compilers\BladeCompiler::compileClassComponentOpening($component, $alias, $data, $hash); + } + + /** + * Compile the end-component statements into valid PHP. + * + * @return string + * @static + */ + public static function compileEndComponentClass() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileEndComponentClass(); + } + + /** + * Sanitize the given component attribute value. + * + * @param mixed $value + * @return mixed + * @static + */ + public static function sanitizeComponentAttribute($value) + { + return \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute($value); + } + + /** + * Compile an end-once block into valid PHP. + * + * @return string + * @static + */ + public static function compileEndOnce() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileEndOnce(); + } + + /** + * Add a handler to be executed before echoing a given class. + * + * @param string|callable $class + * @param callable|null $handler + * @return void + * @static + */ + public static function stringable($class, $handler = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->stringable($class, $handler); + } + + /** + * Compile Blade echos into valid PHP. + * + * @param string $value + * @return string + * @static + */ + public static function compileEchos($value) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileEchos($value); + } + + /** + * Apply the echo handler for the value if it exists. + * + * @param string $value + * @return string + * @static + */ + public static function applyEchoHandler($value) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->applyEchoHandler($value); + } + + } + /** + * + * + * @method static mixed auth(\Illuminate\Http\Request $request) + * @method static mixed validAuthenticationResponse(\Illuminate\Http\Request $request, mixed $result) + * @method static void broadcast(array $channels, string $event, array $payload = []) + * @method static array|null resolveAuthenticatedUser(\Illuminate\Http\Request $request) + * @method static void resolveAuthenticatedUserUsing(\Closure $callback) + * @method static \Illuminate\Broadcasting\Broadcasters\Broadcaster channel(\Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $channel, callable|string $callback, array $options = []) + * @method static \Illuminate\Support\Collection getChannels() + * @see \Illuminate\Broadcasting\BroadcastManager + * @see \Illuminate\Broadcasting\Broadcasters\Broadcaster + */ + class Broadcast { + /** + * Register the routes for handling broadcast channel authentication and sockets. + * + * @param array|null $attributes + * @return void + * @static + */ + public static function routes($attributes = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->routes($attributes); + } + + /** + * Register the routes for handling broadcast user authentication. + * + * @param array|null $attributes + * @return void + * @static + */ + public static function userRoutes($attributes = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->userRoutes($attributes); + } + + /** + * Register the routes for handling broadcast authentication and sockets. + * + * Alias of "routes" method. + * + * @param array|null $attributes + * @return void + * @static + */ + public static function channelRoutes($attributes = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->channelRoutes($attributes); + } + + /** + * Get the socket ID for the given request. + * + * @param \Illuminate\Http\Request|null $request + * @return string|null + * @static + */ + public static function socket($request = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->socket($request); + } + + /** + * Begin sending an anonymous broadcast to the given channels. + * + * @static + */ + public static function on($channels) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->on($channels); + } + + /** + * Begin sending an anonymous broadcast to the given private channels. + * + * @static + */ + public static function private($channel) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->private($channel); + } + + /** + * Begin sending an anonymous broadcast to the given presence channels. + * + * @static + */ + public static function presence($channel) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->presence($channel); + } + + /** + * Begin broadcasting an event. + * + * @param mixed|null $event + * @return \Illuminate\Broadcasting\PendingBroadcast + * @static + */ + public static function event($event = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->event($event); + } + + /** + * Queue the given event for broadcast. + * + * @param mixed $event + * @return void + * @static + */ + public static function queue($event) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->queue($event); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @static + */ + public static function connection($driver = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->connection($driver); + } + + /** + * Get a driver instance. + * + * @param string|null $name + * @return mixed + * @static + */ + public static function driver($name = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->driver($name); + } + + /** + * Get a Pusher instance for the given configuration. + * + * @param array $config + * @return \Pusher\Pusher + * @static + */ + public static function pusher($config) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->pusher($config); + } + + /** + * Get an Ably instance for the given configuration. + * + * @param array $config + * @return \Ably\AblyRest + * @static + */ + public static function ably($config) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->ably($config); + } + + /** + * Get the default driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Disconnect the given disk and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Broadcasting\BroadcastManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + * @static + */ + public static function getApplication() + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->getApplication(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Broadcasting\BroadcastManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->setApplication($app); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Broadcasting\BroadcastManager + * @static + */ + public static function forgetDrivers() + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->forgetDrivers(); + } + + } + /** + * + * + * @see \Illuminate\Bus\Dispatcher + * @see \Illuminate\Support\Testing\Fakes\BusFake + */ + class Bus { + /** + * Dispatch a command to its appropriate handler. + * + * @param mixed $command + * @return mixed + * @static + */ + public static function dispatch($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatch($command); + } + + /** + * Dispatch a command to its appropriate handler in the current process. + * + * Queueable jobs will be dispatched to the "sync" queue. + * + * @param mixed $command + * @param mixed $handler + * @return mixed + * @static + */ + public static function dispatchSync($command, $handler = null) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatchSync($command, $handler); + } + + /** + * Dispatch a command to its appropriate handler in the current process without using the synchronous queue. + * + * @param mixed $command + * @param mixed $handler + * @return mixed + * @static + */ + public static function dispatchNow($command, $handler = null) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatchNow($command, $handler); + } + + /** + * Attempt to find the batch with the given ID. + * + * @param string $batchId + * @return \Illuminate\Bus\Batch|null + * @static + */ + public static function findBatch($batchId) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->findBatch($batchId); + } + + /** + * Create a new batch of queueable jobs. + * + * @param \Illuminate\Support\Collection|array|mixed $jobs + * @return \Illuminate\Bus\PendingBatch + * @static + */ + public static function batch($jobs) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->batch($jobs); + } + + /** + * Create a new chain of queueable jobs. + * + * @param \Illuminate\Support\Collection|array $jobs + * @return \Illuminate\Foundation\Bus\PendingChain + * @static + */ + public static function chain($jobs) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->chain($jobs); + } + + /** + * Determine if the given command has a handler. + * + * @param mixed $command + * @return bool + * @static + */ + public static function hasCommandHandler($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->hasCommandHandler($command); + } + + /** + * Retrieve the handler for a command. + * + * @param mixed $command + * @return bool|mixed + * @static + */ + public static function getCommandHandler($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->getCommandHandler($command); + } + + /** + * Dispatch a command to its appropriate handler behind a queue. + * + * @param mixed $command + * @return mixed + * @throws \RuntimeException + * @static + */ + public static function dispatchToQueue($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatchToQueue($command); + } + + /** + * Dispatch a command to its appropriate handler after the current process. + * + * @param mixed $command + * @param mixed $handler + * @return void + * @static + */ + public static function dispatchAfterResponse($command, $handler = null) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + $instance->dispatchAfterResponse($command, $handler); + } + + /** + * Set the pipes through which commands should be piped before dispatching. + * + * @param array $pipes + * @return \Illuminate\Bus\Dispatcher + * @static + */ + public static function pipeThrough($pipes) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->pipeThrough($pipes); + } + + /** + * Map a command to a handler. + * + * @param array $map + * @return \Illuminate\Bus\Dispatcher + * @static + */ + public static function map($map) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->map($map); + } + + /** + * Specify the jobs that should be dispatched instead of faked. + * + * @param array|string $jobsToDispatch + * @return \Illuminate\Support\Testing\Fakes\BusFake + * @static + */ + public static function except($jobsToDispatch) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->except($jobsToDispatch); + } + + /** + * Assert if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatched($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatched($command, $callback); + } + + /** + * Assert if a job was pushed a number of times. + * + * @param string|\Closure $command + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedTimes($command, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedTimes($command, $times); + } + + /** + * Determine if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatched($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNotDispatched($command, $callback); + } + + /** + * Assert that no jobs were dispatched. + * + * @return void + * @static + */ + public static function assertNothingDispatched() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingDispatched(); + } + + /** + * Assert if a job was explicitly dispatched synchronously based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatchedSync($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedSync($command, $callback); + } + + /** + * Assert if a job was pushed synchronously a number of times. + * + * @param string|\Closure $command + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedSyncTimes($command, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedSyncTimes($command, $times); + } + + /** + * Determine if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatchedSync($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNotDispatchedSync($command, $callback); + } + + /** + * Assert if a job was dispatched after the response was sent based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatchedAfterResponse($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedAfterResponse($command, $callback); + } + + /** + * Assert if a job was pushed after the response was sent a number of times. + * + * @param string|\Closure $command + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedAfterResponseTimes($command, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedAfterResponseTimes($command, $times); + } + + /** + * Determine if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatchedAfterResponse($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNotDispatchedAfterResponse($command, $callback); + } + + /** + * Assert if a chain of jobs was dispatched. + * + * @param array $expectedChain + * @return void + * @static + */ + public static function assertChained($expectedChain) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertChained($expectedChain); + } + + /** + * Assert no chained jobs was dispatched. + * + * @return void + * @static + */ + public static function assertNothingChained() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingChained(); + } + + /** + * Assert if a job was dispatched with an empty chain based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertDispatchedWithoutChain($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedWithoutChain($command, $callback); + } + + /** + * Create a new assertion about a chained batch. + * + * @param \Closure $callback + * @return \Illuminate\Support\Testing\Fakes\ChainedBatchTruthTest + * @static + */ + public static function chainedBatch($callback) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->chainedBatch($callback); + } + + /** + * Assert if a batch was dispatched based on a truth-test callback. + * + * @param callable $callback + * @return void + * @static + */ + public static function assertBatched($callback) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertBatched($callback); + } + + /** + * Assert the number of batches that have been dispatched. + * + * @param int $count + * @return void + * @static + */ + public static function assertBatchCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertBatchCount($count); + } + + /** + * Assert that no batched jobs were dispatched. + * + * @return void + * @static + */ + public static function assertNothingBatched() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingBatched(); + } + + /** + * Assert that no jobs were dispatched, chained, or batched. + * + * @return void + * @static + */ + public static function assertNothingPlaced() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingPlaced(); + } + + /** + * Get all of the jobs matching a truth-test callback. + * + * @param string $command + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatched($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatched($command, $callback); + } + + /** + * Get all of the jobs dispatched synchronously matching a truth-test callback. + * + * @param string $command + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatchedSync($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchedSync($command, $callback); + } + + /** + * Get all of the jobs dispatched after the response was sent matching a truth-test callback. + * + * @param string $command + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatchedAfterResponse($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchedAfterResponse($command, $callback); + } + + /** + * Get all of the pending batches matching a truth-test callback. + * + * @param callable $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function batched($callback) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->batched($callback); + } + + /** + * Determine if there are any stored commands for a given class. + * + * @param string $command + * @return bool + * @static + */ + public static function hasDispatched($command) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->hasDispatched($command); + } + + /** + * Determine if there are any stored commands for a given class. + * + * @param string $command + * @return bool + * @static + */ + public static function hasDispatchedSync($command) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->hasDispatchedSync($command); + } + + /** + * Determine if there are any stored commands for a given class. + * + * @param string $command + * @return bool + * @static + */ + public static function hasDispatchedAfterResponse($command) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->hasDispatchedAfterResponse($command); + } + + /** + * Dispatch an empty job batch for testing. + * + * @param string $name + * @return \Illuminate\Bus\Batch + * @static + */ + public static function dispatchFakeBatch($name = '') + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchFakeBatch($name); + } + + /** + * Record the fake pending batch dispatch. + * + * @param \Illuminate\Bus\PendingBatch $pendingBatch + * @return \Illuminate\Bus\Batch + * @static + */ + public static function recordPendingBatch($pendingBatch) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->recordPendingBatch($pendingBatch); + } + + /** + * Specify if commands should be serialized and restored when being batched. + * + * @param bool $serializeAndRestore + * @return \Illuminate\Support\Testing\Fakes\BusFake + * @static + */ + public static function serializeAndRestore($serializeAndRestore = true) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->serializeAndRestore($serializeAndRestore); + } + + /** + * Get the batches that have been dispatched. + * + * @return array + * @static + */ + public static function dispatchedBatches() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchedBatches(); + } + + } + /** + * + * + * @see \Illuminate\Cache\CacheManager + * @see \Illuminate\Cache\Repository + */ + class Cache { + /** + * Get a cache store instance by name, wrapped in a repository. + * + * @param string|null $name + * @return \Illuminate\Contracts\Cache\Repository + * @static + */ + public static function store($name = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->store($name); + } + + /** + * Get a cache driver instance. + * + * @param string|null $driver + * @return \Illuminate\Contracts\Cache\Repository + * @static + */ + public static function driver($driver = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->driver($driver); + } + + /** + * Resolve the given store. + * + * @param string $name + * @return \Illuminate\Contracts\Cache\Repository + * @throws \InvalidArgumentException + * @static + */ + public static function resolve($name) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->resolve($name); + } + + /** + * Build a cache repository with the given configuration. + * + * @param array $config + * @return \Illuminate\Cache\Repository + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->build($config); + } + + /** + * Create a new cache repository with the given implementation. + * + * @param \Illuminate\Contracts\Cache\Store $store + * @param array $config + * @return \Illuminate\Cache\Repository + * @static + */ + public static function repository($store, $config = []) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->repository($store, $config); + } + + /** + * Re-set the event dispatcher on all resolved cache repositories. + * + * @return void + * @static + */ + public static function refreshEventDispatcher() + { + /** @var \Illuminate\Cache\CacheManager $instance */ + $instance->refreshEventDispatcher(); + } + + /** + * Get the default cache driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default cache driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Unset the given driver instances. + * + * @param array|string|null $name + * @return \Illuminate\Cache\CacheManager + * @static + */ + public static function forgetDriver($name = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->forgetDriver($name); + } + + /** + * Disconnect the given driver and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @param-closure-this $this $callback + * @return \Illuminate\Cache\CacheManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Cache\CacheManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->setApplication($app); + } + + /** + * Determine if an item exists in the cache. + * + * @param array|string $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->has($key); + } + + /** + * Determine if an item doesn't exist in the cache. + * + * @param string $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->missing($key); + } + + /** + * Retrieve an item from the cache by key. + * + * @param array|string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->get($key, $default); + } + + /** + * Retrieve multiple items from the cache by key. + * + * Items not found in the cache will have a null value. + * + * @param array $keys + * @return array + * @static + */ + public static function many($keys) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->many($keys); + } + + /** + * Obtains multiple cache items by their unique keys. + * + * @return iterable + * @param iterable $keys A list of keys that can be obtained in a single operation. + * @param mixed $default Default value to return for keys that do not exist. + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + * @static + */ + public static function getMultiple($keys, $default = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getMultiple($keys, $default); + } + + /** + * Retrieve an item from the cache and delete it. + * + * @param array|string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pull($key, $default = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->pull($key, $default); + } + + /** + * Store an item in the cache. + * + * @param array|string $key + * @param mixed $value + * @param \DateTimeInterface|\DateInterval|int|null $ttl + * @return bool + * @static + */ + public static function put($key, $value, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->put($key, $value, $ttl); + } + + /** + * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. + * + * @return bool + * @param string $key The key of the item to store. + * @param mixed $value The value of the item to store, must be serializable. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * @return bool True on success and false on failure. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + * @static + */ + public static function set($key, $value, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->set($key, $value, $ttl); + } + + /** + * Store multiple items in the cache for a given number of seconds. + * + * @param array $values + * @param \DateTimeInterface|\DateInterval|int|null $ttl + * @return bool + * @static + */ + public static function putMany($values, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->putMany($values, $ttl); + } + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @return bool + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * @return bool True on success and false on failure. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + * @static + */ + public static function setMultiple($values, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->setMultiple($values, $ttl); + } + + /** + * Store an item in the cache if the key does not exist. + * + * @param string $key + * @param mixed $value + * @param \DateTimeInterface|\DateInterval|int|null $ttl + * @return bool + * @static + */ + public static function add($key, $value, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->add($key, $value, $ttl); + } + + /** + * Increment the value of an item in the cache. + * + * @param string $key + * @param mixed $value + * @return int|bool + * @static + */ + public static function increment($key, $value = 1) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->increment($key, $value); + } + + /** + * Decrement the value of an item in the cache. + * + * @param string $key + * @param mixed $value + * @return int|bool + * @static + */ + public static function decrement($key, $value = 1) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->decrement($key, $value); + } + + /** + * Store an item in the cache indefinitely. + * + * @param string $key + * @param mixed $value + * @return bool + * @static + */ + public static function forever($key, $value) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->forever($key, $value); + } + + /** + * Get an item from the cache, or execute the given Closure and store the result. + * + * @template TCacheValue + * @param string $key + * @param \Closure|\DateTimeInterface|\DateInterval|int|null $ttl + * @param \Closure(): TCacheValue $callback + * @return TCacheValue + * @static + */ + public static function remember($key, $ttl, $callback) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->remember($key, $ttl, $callback); + } + + /** + * Get an item from the cache, or execute the given Closure and store the result forever. + * + * @template TCacheValue + * @param string $key + * @param \Closure(): TCacheValue $callback + * @return TCacheValue + * @static + */ + public static function sear($key, $callback) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->sear($key, $callback); + } + + /** + * Get an item from the cache, or execute the given Closure and store the result forever. + * + * @template TCacheValue + * @param string $key + * @param \Closure(): TCacheValue $callback + * @return TCacheValue + * @static + */ + public static function rememberForever($key, $callback) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->rememberForever($key, $callback); + } + + /** + * Retrieve an item from the cache by key, refreshing it in the background if it is stale. + * + * @template TCacheValue + * @param string $key + * @param array{ 0: \DateTimeInterface|\DateInterval|int, 1: \DateTimeInterface|\DateInterval|int } $ttl + * @param (callable(): TCacheValue) $callback + * @param array{ seconds?: int, owner?: string }|null $lock + * @return TCacheValue + * @static + */ + public static function flexible($key, $ttl, $callback, $lock = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->flexible($key, $ttl, $callback, $lock); + } + + /** + * Remove an item from the cache. + * + * @param string $key + * @return bool + * @static + */ + public static function forget($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->forget($key); + } + + /** + * Delete an item from the cache by its unique key. + * + * @return bool + * @param string $key The unique cache key of the item to delete. + * @return bool True if the item was successfully removed. False if there was an error. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + * @static + */ + public static function delete($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->delete($key); + } + + /** + * Deletes multiple cache items in a single operation. + * + * @return bool + * @param iterable $keys A list of string-based keys to be deleted. + * @return bool True if the items were successfully removed. False if there was an error. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + * @static + */ + public static function deleteMultiple($keys) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->deleteMultiple($keys); + } + + /** + * Wipes clean the entire cache's keys. + * + * @return bool + * @return bool True on success and false on failure. + * @static + */ + public static function clear() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->clear(); + } + + /** + * Begin executing a new tags operation if the store supports it. + * + * @param array|mixed $names + * @return \Illuminate\Cache\TaggedCache + * @throws \BadMethodCallException + * @static + */ + public static function tags($names) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->tags($names); + } + + /** + * Get the name of the cache store. + * + * @return string|null + * @static + */ + public static function getName() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getName(); + } + + /** + * Determine if the current store supports tags. + * + * @return bool + * @static + */ + public static function supportsTags() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->supportsTags(); + } + + /** + * Get the default cache time. + * + * @return int|null + * @static + */ + public static function getDefaultCacheTime() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getDefaultCacheTime(); + } + + /** + * Set the default cache time in seconds. + * + * @param int|null $seconds + * @return \Illuminate\Cache\Repository + * @static + */ + public static function setDefaultCacheTime($seconds) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->setDefaultCacheTime($seconds); + } + + /** + * Get the cache store implementation. + * + * @return \Illuminate\Contracts\Cache\Store + * @static + */ + public static function getStore() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getStore(); + } + + /** + * Set the cache store implementation. + * + * @param \Illuminate\Contracts\Cache\Store $store + * @return static + * @static + */ + public static function setStore($store) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->setStore($store); + } + + /** + * Get the event dispatcher instance. + * + * @return \Illuminate\Contracts\Events\Dispatcher|null + * @static + */ + public static function getEventDispatcher() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getEventDispatcher(); + } + + /** + * Set the event dispatcher instance. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + * @static + */ + public static function setEventDispatcher($events) + { + /** @var \Illuminate\Cache\Repository $instance */ + $instance->setEventDispatcher($events); + } + + /** + * Determine if a cached value exists. + * + * @param string $key + * @return bool + * @static + */ + public static function offsetExists($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->offsetExists($key); + } + + /** + * Retrieve an item from the cache by key. + * + * @param string $key + * @return mixed + * @static + */ + public static function offsetGet($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->offsetGet($key); + } + + /** + * Store an item in the cache for the default time. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($key, $value) + { + /** @var \Illuminate\Cache\Repository $instance */ + $instance->offsetSet($key, $value); + } + + /** + * Remove an item from the cache. + * + * @param string $key + * @return void + * @static + */ + public static function offsetUnset($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + $instance->offsetUnset($key); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Cache\Repository::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Cache\Repository::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Cache\Repository::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Cache\Repository::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->macroCall($method, $parameters); + } + + /** + * Get a lock instance. + * + * @param string $name + * @param int $seconds + * @param string|null $owner + * @return \Illuminate\Contracts\Cache\Lock + * @static + */ + public static function lock($name, $seconds = 0, $owner = null) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->lock($name, $seconds, $owner); + } + + /** + * Restore a lock instance using the owner identifier. + * + * @param string $name + * @param string $owner + * @return \Illuminate\Contracts\Cache\Lock + * @static + */ + public static function restoreLock($name, $owner) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->restoreLock($name, $owner); + } + + /** + * Remove an item from the cache if it is expired. + * + * @param string $key + * @return bool + * @static + */ + public static function forgetIfExpired($key) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->forgetIfExpired($key); + } + + /** + * Remove all items from the cache. + * + * @return bool + * @static + */ + public static function flush() + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->flush(); + } + + /** + * Get the underlying database connection. + * + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function getConnection() + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->getConnection(); + } + + /** + * Specify the name of the connection that should be used to manage locks. + * + * @param \Illuminate\Database\ConnectionInterface $connection + * @return \Illuminate\Cache\DatabaseStore + * @static + */ + public static function setLockConnection($connection) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->setLockConnection($connection); + } + + /** + * Get the cache key prefix. + * + * @return string + * @static + */ + public static function getPrefix() + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->getPrefix(); + } + + /** + * Set the cache key prefix. + * + * @param string $prefix + * @return void + * @static + */ + public static function setPrefix($prefix) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + $instance->setPrefix($prefix); + } + + } + /** + * + * + * @see \Illuminate\Config\Repository + */ + class Config { + /** + * Determine if the given configuration value exists. + * + * @param string $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->has($key); + } + + /** + * Get the specified configuration value. + * + * @param array|string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->get($key, $default); + } + + /** + * Get many configuration values. + * + * @param array $keys + * @return array + * @static + */ + public static function getMany($keys) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->getMany($keys); + } + + /** + * Get the specified string configuration value. + * + * @param string $key + * @param (\Closure():(string|null))|string|null $default + * @return string + * @static + */ + public static function string($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->string($key, $default); + } + + /** + * Get the specified integer configuration value. + * + * @param string $key + * @param (\Closure():(int|null))|int|null $default + * @return int + * @static + */ + public static function integer($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->integer($key, $default); + } + + /** + * Get the specified float configuration value. + * + * @param string $key + * @param (\Closure():(float|null))|float|null $default + * @return float + * @static + */ + public static function float($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->float($key, $default); + } + + /** + * Get the specified boolean configuration value. + * + * @param string $key + * @param (\Closure():(bool|null))|bool|null $default + * @return bool + * @static + */ + public static function boolean($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->boolean($key, $default); + } + + /** + * Get the specified array configuration value. + * + * @param string $key + * @param (\Closure():(array|null))|array|null $default + * @return array + * @static + */ + public static function array($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->array($key, $default); + } + + /** + * Set a given configuration value. + * + * @param array|string $key + * @param mixed $value + * @return void + * @static + */ + public static function set($key, $value = null) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->set($key, $value); + } + + /** + * Prepend a value onto an array configuration value. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function prepend($key, $value) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->prepend($key, $value); + } + + /** + * Push a value onto an array configuration value. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function push($key, $value) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->push($key, $value); + } + + /** + * Get all of the configuration items for the application. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->all(); + } + + /** + * Determine if the given configuration option exists. + * + * @param string $key + * @return bool + * @static + */ + public static function offsetExists($key) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->offsetExists($key); + } + + /** + * Get a configuration option. + * + * @param string $key + * @return mixed + * @static + */ + public static function offsetGet($key) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->offsetGet($key); + } + + /** + * Set a configuration option. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($key, $value) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->offsetSet($key, $value); + } + + /** + * Unset a configuration option. + * + * @param string $key + * @return void + * @static + */ + public static function offsetUnset($key) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->offsetUnset($key); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Config\Repository::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Config\Repository::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Config\Repository::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Config\Repository::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Log\Context\Repository + */ + class Context { + /** + * Determine if the given key exists. + * + * @param string $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->has($key); + } + + /** + * Determine if the given key is missing. + * + * @param string $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->missing($key); + } + + /** + * Determine if the given key exists within the hidden context data. + * + * @param string $key + * @return bool + * @static + */ + public static function hasHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hasHidden($key); + } + + /** + * Determine if the given key is missing within the hidden context data. + * + * @param string $key + * @return bool + * @static + */ + public static function missingHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->missingHidden($key); + } + + /** + * Retrieve all the context data. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->all(); + } + + /** + * Retrieve all the hidden context data. + * + * @return array + * @static + */ + public static function allHidden() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->allHidden(); + } + + /** + * Retrieve the given key's value. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->get($key, $default); + } + + /** + * Retrieve the given key's hidden value. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function getHidden($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->getHidden($key, $default); + } + + /** + * Retrieve the given key's value and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pull($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pull($key, $default); + } + + /** + * Retrieve the given key's hidden value and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pullHidden($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pullHidden($key, $default); + } + + /** + * Retrieve only the values of the given keys. + * + * @param array $keys + * @return array + * @static + */ + public static function only($keys) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->only($keys); + } + + /** + * Retrieve only the hidden values of the given keys. + * + * @param array $keys + * @return array + * @static + */ + public static function onlyHidden($keys) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->onlyHidden($keys); + } + + /** + * Add a context value. + * + * @param string|array $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function add($key, $value = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->add($key, $value); + } + + /** + * Add a hidden context value. + * + * @param string|array $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function addHidden($key, $value = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->addHidden($key, $value); + } + + /** + * Forget the given context key. + * + * @param string|array $key + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function forget($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->forget($key); + } + + /** + * Forget the given hidden context key. + * + * @param string|array $key + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function forgetHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->forgetHidden($key); + } + + /** + * Add a context value if it does not exist yet. + * + * @param string $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function addIf($key, $value) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->addIf($key, $value); + } + + /** + * Add a hidden context value if it does not exist yet. + * + * @param string $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function addHiddenIf($key, $value) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->addHiddenIf($key, $value); + } + + /** + * Push the given values onto the key's stack. + * + * @param string $key + * @param mixed $values + * @return \Illuminate\Log\Context\Repository + * @throws \RuntimeException + * @static + */ + public static function push($key, ...$values) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->push($key, ...$values); + } + + /** + * Pop the latest value from the key's stack. + * + * @param string $key + * @return mixed + * @throws \RuntimeException + * @static + */ + public static function pop($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pop($key); + } + + /** + * Push the given hidden values onto the key's stack. + * + * @param string $key + * @param mixed $values + * @return \Illuminate\Log\Context\Repository + * @throws \RuntimeException + * @static + */ + public static function pushHidden($key, ...$values) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pushHidden($key, ...$values); + } + + /** + * Pop the latest hidden value from the key's stack. + * + * @param string $key + * @return mixed + * @throws \RuntimeException + * @static + */ + public static function popHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->popHidden($key); + } + + /** + * Increment a context counter. + * + * @param string $key + * @param int $amount + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function increment($key, $amount = 1) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->increment($key, $amount); + } + + /** + * Decrement a context counter. + * + * @param string $key + * @param int $amount + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function decrement($key, $amount = 1) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->decrement($key, $amount); + } + + /** + * Determine if the given value is in the given stack. + * + * @param string $key + * @param mixed $value + * @param bool $strict + * @return bool + * @throws \RuntimeException + * @static + */ + public static function stackContains($key, $value, $strict = false) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->stackContains($key, $value, $strict); + } + + /** + * Determine if the given value is in the given hidden stack. + * + * @param string $key + * @param mixed $value + * @param bool $strict + * @return bool + * @throws \RuntimeException + * @static + */ + public static function hiddenStackContains($key, $value, $strict = false) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hiddenStackContains($key, $value, $strict); + } + + /** + * Run the callback function with the given context values and restore the original context state when complete. + * + * @param callable $callback + * @param array $data + * @param array $hidden + * @return mixed + * @static + */ + public static function scope($callback, $data = [], $hidden = []) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->scope($callback, $data, $hidden); + } + + /** + * Determine if the repository is empty. + * + * @return bool + * @static + */ + public static function isEmpty() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->isEmpty(); + } + + /** + * Execute the given callback when context is about to be dehydrated. + * + * @param callable $callback + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function dehydrating($callback) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->dehydrating($callback); + } + + /** + * Execute the given callback when context has been hydrated. + * + * @param callable $callback + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function hydrated($callback) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hydrated($callback); + } + + /** + * Handle unserialize exceptions using the given callback. + * + * @param callable|null $callback + * @return static + * @static + */ + public static function handleUnserializeExceptionsUsing($callback) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->handleUnserializeExceptionsUsing($callback); + } + + /** + * Flush all context data. + * + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function flush() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->flush(); + } + + /** + * Dehydrate the context data. + * + * @internal + * @return \Illuminate\Log\Context\?array + * @static + */ + public static function dehydrate() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->dehydrate(); + } + + /** + * Hydrate the context instance. + * + * @internal + * @param \Illuminate\Log\Context\?array $context + * @return \Illuminate\Log\Context\Repository + * @throws \RuntimeException + * @static + */ + public static function hydrate($context) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hydrate($context); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Log\Context\Repository::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Log\Context\Repository::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Log\Context\Repository::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Log\Context\Repository::flushMacros(); + } + + /** + * Restore the model from the model identifier instance. + * + * @param \Illuminate\Contracts\Database\ModelIdentifier $value + * @return \Illuminate\Database\Eloquent\Model + * @static + */ + public static function restoreModel($value) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->restoreModel($value); + } + + } + /** + * + * + * @see \Illuminate\Cookie\CookieJar + */ + class Cookie { + /** + * Create a new cookie instance. + * + * @param string $name + * @param string $value + * @param int $minutes + * @param string|null $path + * @param string|null $domain + * @param bool|null $secure + * @param bool $httpOnly + * @param bool $raw + * @param string|null $sameSite + * @return \Symfony\Component\HttpFoundation\Cookie + * @static + */ + public static function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->make($name, $value, $minutes, $path, $domain, $secure, $httpOnly, $raw, $sameSite); + } + + /** + * Create a cookie that lasts "forever" (400 days). + * + * @param string $name + * @param string $value + * @param string|null $path + * @param string|null $domain + * @param bool|null $secure + * @param bool $httpOnly + * @param bool $raw + * @param string|null $sameSite + * @return \Symfony\Component\HttpFoundation\Cookie + * @static + */ + public static function forever($name, $value, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->forever($name, $value, $path, $domain, $secure, $httpOnly, $raw, $sameSite); + } + + /** + * Expire the given cookie. + * + * @param string $name + * @param string|null $path + * @param string|null $domain + * @return \Symfony\Component\HttpFoundation\Cookie + * @static + */ + public static function forget($name, $path = null, $domain = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->forget($name, $path, $domain); + } + + /** + * Determine if a cookie has been queued. + * + * @param string $key + * @param string|null $path + * @return bool + * @static + */ + public static function hasQueued($key, $path = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->hasQueued($key, $path); + } + + /** + * Get a queued cookie instance. + * + * @param string $key + * @param mixed $default + * @param string|null $path + * @return \Symfony\Component\HttpFoundation\Cookie|null + * @static + */ + public static function queued($key, $default = null, $path = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->queued($key, $default, $path); + } + + /** + * Queue a cookie to send with the next response. + * + * @param mixed $parameters + * @return void + * @static + */ + public static function queue(...$parameters) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + $instance->queue(...$parameters); + } + + /** + * Queue a cookie to expire with the next response. + * + * @param string $name + * @param string|null $path + * @param string|null $domain + * @return void + * @static + */ + public static function expire($name, $path = null, $domain = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + $instance->expire($name, $path, $domain); + } + + /** + * Remove a cookie from the queue. + * + * @param string $name + * @param string|null $path + * @return void + * @static + */ + public static function unqueue($name, $path = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + $instance->unqueue($name, $path); + } + + /** + * Set the default path and domain for the jar. + * + * @param string $path + * @param string|null $domain + * @param bool|null $secure + * @param string|null $sameSite + * @return \Illuminate\Cookie\CookieJar + * @static + */ + public static function setDefaultPathAndDomain($path, $domain, $secure = false, $sameSite = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->setDefaultPathAndDomain($path, $domain, $secure, $sameSite); + } + + /** + * Get the cookies which have been queued for the next request. + * + * @return \Symfony\Component\HttpFoundation\Cookie[] + * @static + */ + public static function getQueuedCookies() + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->getQueuedCookies(); + } + + /** + * Flush the cookies which have been queued for the next request. + * + * @return \Illuminate\Cookie\CookieJar + * @static + */ + public static function flushQueuedCookies() + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->flushQueuedCookies(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Cookie\CookieJar::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Cookie\CookieJar::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Cookie\CookieJar::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Cookie\CookieJar::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Encryption\Encrypter + */ + class Crypt { + /** + * Determine if the given key and cipher combination is valid. + * + * @param string $key + * @param string $cipher + * @return bool + * @static + */ + public static function supported($key, $cipher) + { + return \Illuminate\Encryption\Encrypter::supported($key, $cipher); + } + + /** + * Create a new encryption key for the given cipher. + * + * @param string $cipher + * @return string + * @static + */ + public static function generateKey($cipher) + { + return \Illuminate\Encryption\Encrypter::generateKey($cipher); + } + + /** + * Encrypt the given value. + * + * @param mixed $value + * @param bool $serialize + * @return string + * @throws \Illuminate\Contracts\Encryption\EncryptException + * @static + */ + public static function encrypt($value, $serialize = true) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->encrypt($value, $serialize); + } + + /** + * Encrypt a string without serialization. + * + * @param string $value + * @return string + * @throws \Illuminate\Contracts\Encryption\EncryptException + * @static + */ + public static function encryptString($value) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->encryptString($value); + } + + /** + * Decrypt the given value. + * + * @param string $payload + * @param bool $unserialize + * @return mixed + * @throws \Illuminate\Contracts\Encryption\DecryptException + * @static + */ + public static function decrypt($payload, $unserialize = true) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->decrypt($payload, $unserialize); + } + + /** + * Decrypt the given string without unserialization. + * + * @param string $payload + * @return string + * @throws \Illuminate\Contracts\Encryption\DecryptException + * @static + */ + public static function decryptString($payload) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->decryptString($payload); + } + + /** + * Get the encryption key that the encrypter is currently using. + * + * @return string + * @static + */ + public static function getKey() + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->getKey(); + } + + /** + * Get the current encryption key and all previous encryption keys. + * + * @return array + * @static + */ + public static function getAllKeys() + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->getAllKeys(); + } + + /** + * Get the previous encryption keys. + * + * @return array + * @static + */ + public static function getPreviousKeys() + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->getPreviousKeys(); + } + + /** + * Set the previous / legacy encryption keys that should be utilized if decryption fails. + * + * @param array $keys + * @return \Illuminate\Encryption\Encrypter + * @static + */ + public static function previousKeys($keys) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->previousKeys($keys); + } + + } + /** + * + * + * @see https://carbon.nesbot.com/docs/ + * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php + * @method static \Illuminate\Support\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) + * @method static \Illuminate\Support\Carbon|false createFromFormat($format, $time, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimeString($time, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestamp($timestamp, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMs($timestamp, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampUTC($timestamp) + * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) + * @method static \Illuminate\Support\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) + * @method static void disableHumanDiffOption($humanDiffOption) + * @method static void enableHumanDiffOption($humanDiffOption) + * @method static mixed executeWithLocale($locale, $func) + * @method static \Illuminate\Support\Carbon fromSerialized($value) + * @method static array getAvailableLocales() + * @method static array getDays() + * @method static int getHumanDiffOptions() + * @method static array getIsoUnits() + * @method static array getLastErrors() + * @method static string getLocale() + * @method static int getMidDayAt() + * @method static \Illuminate\Support\Carbon|null getTestNow() + * @method static \Symfony\Contracts\Translation\TranslatorInterface getTranslator() + * @method static int getWeekEndsAt() + * @method static int getWeekStartsAt() + * @method static array getWeekendDays() + * @method static bool hasFormat($date, $format) + * @method static bool hasMacro($name) + * @method static bool hasRelativeKeywords($time) + * @method static bool hasTestNow() + * @method static \Illuminate\Support\Carbon instance($date) + * @method static bool isImmutable() + * @method static bool isModifiableUnit($unit) + * @method static bool isMutable() + * @method static bool isStrictModeEnabled() + * @method static bool localeHasDiffOneDayWords($locale) + * @method static bool localeHasDiffSyntax($locale) + * @method static bool localeHasDiffTwoDayWords($locale) + * @method static bool localeHasPeriodSyntax($locale) + * @method static bool localeHasShortUnits($locale) + * @method static void macro($name, $macro) + * @method static \Illuminate\Support\Carbon|null make($var) + * @method static \Illuminate\Support\Carbon maxValue() + * @method static \Illuminate\Support\Carbon minValue() + * @method static void mixin($mixin) + * @method static \Illuminate\Support\Carbon now($timezone = null) + * @method static \Illuminate\Support\Carbon parse($time = null, $timezone = null) + * @method static string pluralUnit(string $unit) + * @method static void resetMonthsOverflow() + * @method static void resetToStringFormat() + * @method static void resetYearsOverflow() + * @method static void serializeUsing($callback) + * @method static void setHumanDiffOptions($humanDiffOptions) + * @method static bool setLocale($locale) + * @method static void setMidDayAt($hour) + * @method static void setTestNow($testNow = null) + * @method static void setToStringFormat($format) + * @method static void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) + * @method static void setUtf8($utf8) + * @method static void setWeekEndsAt($day) + * @method static void setWeekStartsAt($day) + * @method static void setWeekendDays($days) + * @method static bool shouldOverflowMonths() + * @method static bool shouldOverflowYears() + * @method static string singularUnit(string $unit) + * @method static \Illuminate\Support\Carbon today($timezone = null) + * @method static \Illuminate\Support\Carbon tomorrow($timezone = null) + * @method static void useMonthsOverflow($monthsOverflow = true) + * @method static void useStrictMode($strictModeEnabled = true) + * @method static void useYearsOverflow($yearsOverflow = true) + * @method static \Illuminate\Support\Carbon yesterday($timezone = null) + * @see \Illuminate\Support\DateFactory + */ + class Date { + /** + * Use the given handler when generating dates (class name, callable, or factory). + * + * @param mixed $handler + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function use($handler) + { + return \Illuminate\Support\DateFactory::use($handler); + } + + /** + * Use the default date class when generating dates. + * + * @return void + * @static + */ + public static function useDefault() + { + \Illuminate\Support\DateFactory::useDefault(); + } + + /** + * Execute the given callable on each date creation. + * + * @param callable $callable + * @return void + * @static + */ + public static function useCallable($callable) + { + \Illuminate\Support\DateFactory::useCallable($callable); + } + + /** + * Use the given date type (class) when generating dates. + * + * @param string $dateClass + * @return void + * @static + */ + public static function useClass($dateClass) + { + \Illuminate\Support\DateFactory::useClass($dateClass); + } + + /** + * Use the given Carbon factory when generating dates. + * + * @param object $factory + * @return void + * @static + */ + public static function useFactory($factory) + { + \Illuminate\Support\DateFactory::useFactory($factory); + } + + } + /** + * + * + * @see \Illuminate\Database\DatabaseManager + */ + class DB { + /** + * Get a database connection instance. + * + * @param string|null $name + * @return \Illuminate\Database\Connection + * @static + */ + public static function connection($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->connection($name); + } + + /** + * Build a database connection instance from the given configuration. + * + * @param array $config + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->build($config); + } + + /** + * Calculate the dynamic connection name for an on-demand connection based on its configuration. + * + * @param array $config + * @return string + * @static + */ + public static function calculateDynamicConnectionName($config) + { + return \Illuminate\Database\DatabaseManager::calculateDynamicConnectionName($config); + } + + /** + * Get a database connection instance from the given configuration. + * + * @param string $name + * @param array $config + * @param bool $force + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function connectUsing($name, $config, $force = false) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->connectUsing($name, $config, $force); + } + + /** + * Disconnect from the given database and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->purge($name); + } + + /** + * Disconnect from the given database. + * + * @param string|null $name + * @return void + * @static + */ + public static function disconnect($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->disconnect($name); + } + + /** + * Reconnect to the given database. + * + * @param string|null $name + * @return \Illuminate\Database\Connection + * @static + */ + public static function reconnect($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->reconnect($name); + } + + /** + * Set the default database connection for the callback execution. + * + * @param string $name + * @param callable $callback + * @return mixed + * @static + */ + public static function usingConnection($name, $callback) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->usingConnection($name, $callback); + } + + /** + * Get the default connection name. + * + * @return string + * @static + */ + public static function getDefaultConnection() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->getDefaultConnection(); + } + + /** + * Set the default connection name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultConnection($name) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->setDefaultConnection($name); + } + + /** + * Get all of the supported drivers. + * + * @return string[] + * @static + */ + public static function supportedDrivers() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->supportedDrivers(); + } + + /** + * Get all of the drivers that are actually available. + * + * @return string[] + * @static + */ + public static function availableDrivers() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->availableDrivers(); + } + + /** + * Register an extension connection resolver. + * + * @param string $name + * @param callable $resolver + * @return void + * @static + */ + public static function extend($name, $resolver) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->extend($name, $resolver); + } + + /** + * Remove an extension connection resolver. + * + * @param string $name + * @return void + * @static + */ + public static function forgetExtension($name) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->forgetExtension($name); + } + + /** + * Return all of the created connections. + * + * @return array + * @static + */ + public static function getConnections() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->getConnections(); + } + + /** + * Set the database reconnector callback. + * + * @param callable $reconnector + * @return void + * @static + */ + public static function setReconnector($reconnector) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->setReconnector($reconnector); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Database\DatabaseManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->setApplication($app); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Database\DatabaseManager::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Database\DatabaseManager::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Database\DatabaseManager::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Database\DatabaseManager::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->macroCall($method, $parameters); + } + + /** + * Get a human-readable name for the given connection driver. + * + * @return string + * @static + */ + public static function getDriverTitle() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getDriverTitle(); + } + + /** + * Run an insert statement against the database. + * + * @param string $query + * @param array $bindings + * @param string|null $sequence + * @return bool + * @static + */ + public static function insert($query, $bindings = [], $sequence = null) + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->insert($query, $bindings, $sequence); + } + + /** + * Get the connection's last insert ID. + * + * @return string|int|null + * @static + */ + public static function getLastInsertId() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getLastInsertId(); + } + + /** + * Determine if the connected database is a MariaDB database. + * + * @return bool + * @static + */ + public static function isMaria() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->isMaria(); + } + + /** + * Get the server version for the connection. + * + * @return string + * @static + */ + public static function getServerVersion() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getServerVersion(); + } + + /** + * Get a schema builder instance for the connection. + * + * @return \Illuminate\Database\Schema\MySqlBuilder + * @static + */ + public static function getSchemaBuilder() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getSchemaBuilder(); + } + + /** + * Get the schema state for the connection. + * + * @param \Illuminate\Filesystem\Filesystem|null $files + * @param callable|null $processFactory + * @return \Illuminate\Database\Schema\MySqlSchemaState + * @static + */ + public static function getSchemaState($files = null, $processFactory = null) + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getSchemaState($files, $processFactory); + } + + /** + * Set the query grammar to the default implementation. + * + * @return void + * @static + */ + public static function useDefaultQueryGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->useDefaultQueryGrammar(); + } + + /** + * Set the schema grammar to the default implementation. + * + * @return void + * @static + */ + public static function useDefaultSchemaGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->useDefaultSchemaGrammar(); + } + + /** + * Set the query post processor to the default implementation. + * + * @return void + * @static + */ + public static function useDefaultPostProcessor() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->useDefaultPostProcessor(); + } + + /** + * Begin a fluent query against a database table. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Contracts\Database\Query\Expression|string $table + * @param string|null $as + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function table($table, $as = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->table($table, $as); + } + + /** + * Get a new query builder instance. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function query() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->query(); + } + + /** + * Run a select statement and return a single result. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return mixed + * @static + */ + public static function selectOne($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->selectOne($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement and return the first column of the first row. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return mixed + * @throws \Illuminate\Database\MultipleColumnsSelectedException + * @static + */ + public static function scalar($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->scalar($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement against the database. + * + * @param string $query + * @param array $bindings + * @return array + * @static + */ + public static function selectFromWriteConnection($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->selectFromWriteConnection($query, $bindings); + } + + /** + * Run a select statement against the database. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return array + * @static + */ + public static function select($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->select($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement against the database and returns all of the result sets. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return array + * @static + */ + public static function selectResultSets($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->selectResultSets($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement against the database and returns a generator. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return \Generator + * @static + */ + public static function cursor($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->cursor($query, $bindings, $useReadPdo); + } + + /** + * Run an update statement against the database. + * + * @param string $query + * @param array $bindings + * @return int + * @static + */ + public static function update($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->update($query, $bindings); + } + + /** + * Run a delete statement against the database. + * + * @param string $query + * @param array $bindings + * @return int + * @static + */ + public static function delete($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->delete($query, $bindings); + } + + /** + * Execute an SQL statement and return the boolean result. + * + * @param string $query + * @param array $bindings + * @return bool + * @static + */ + public static function statement($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->statement($query, $bindings); + } + + /** + * Run an SQL statement and get the number of rows affected. + * + * @param string $query + * @param array $bindings + * @return int + * @static + */ + public static function affectingStatement($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->affectingStatement($query, $bindings); + } + + /** + * Run a raw, unprepared query against the PDO connection. + * + * @param string $query + * @return bool + * @static + */ + public static function unprepared($query) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->unprepared($query); + } + + /** + * Get the number of open connections for the database. + * + * @return int|null + * @static + */ + public static function threadCount() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->threadCount(); + } + + /** + * Execute the given callback in "dry run" mode. + * + * @param \Closure $callback + * @return array + * @static + */ + public static function pretend($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->pretend($callback); + } + + /** + * Execute the given callback without "pretending". + * + * @param \Closure $callback + * @return mixed + * @static + */ + public static function withoutPretending($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->withoutPretending($callback); + } + + /** + * Bind values to their parameters in the given statement. + * + * @param \PDOStatement $statement + * @param array $bindings + * @return void + * @static + */ + public static function bindValues($statement, $bindings) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->bindValues($statement, $bindings); + } + + /** + * Prepare the query bindings for execution. + * + * @param array $bindings + * @return array + * @static + */ + public static function prepareBindings($bindings) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->prepareBindings($bindings); + } + + /** + * Log a query in the connection's query log. + * + * @param string $query + * @param array $bindings + * @param float|null $time + * @return void + * @static + */ + public static function logQuery($query, $bindings, $time = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->logQuery($query, $bindings, $time); + } + + /** + * Register a callback to be invoked when the connection queries for longer than a given amount of time. + * + * @param \DateTimeInterface|\Carbon\CarbonInterval|float|int $threshold + * @param callable $handler + * @return void + * @static + */ + public static function whenQueryingForLongerThan($threshold, $handler) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->whenQueryingForLongerThan($threshold, $handler); + } + + /** + * Allow all the query duration handlers to run again, even if they have already run. + * + * @return void + * @static + */ + public static function allowQueryDurationHandlersToRunAgain() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->allowQueryDurationHandlersToRunAgain(); + } + + /** + * Get the duration of all run queries in milliseconds. + * + * @return float + * @static + */ + public static function totalQueryDuration() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->totalQueryDuration(); + } + + /** + * Reset the duration of all run queries. + * + * @return void + * @static + */ + public static function resetTotalQueryDuration() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->resetTotalQueryDuration(); + } + + /** + * Reconnect to the database if a PDO connection is missing. + * + * @return void + * @static + */ + public static function reconnectIfMissingConnection() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->reconnectIfMissingConnection(); + } + + /** + * Register a hook to be run just before a database transaction is started. + * + * @param \Closure $callback + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function beforeStartingTransaction($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->beforeStartingTransaction($callback); + } + + /** + * Register a hook to be run just before a database query is executed. + * + * @param \Closure $callback + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function beforeExecuting($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->beforeExecuting($callback); + } + + /** + * Register a database query listener with the connection. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function listen($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->listen($callback); + } + + /** + * Get a new raw query expression. + * + * @param mixed $value + * @return \Illuminate\Contracts\Database\Query\Expression + * @static + */ + public static function raw($value) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->raw($value); + } + + /** + * Escape a value for safe SQL embedding. + * + * @param string|float|int|bool|null $value + * @param bool $binary + * @return string + * @static + */ + public static function escape($value, $binary = false) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->escape($value, $binary); + } + + /** + * Determine if the database connection has modified any database records. + * + * @return bool + * @static + */ + public static function hasModifiedRecords() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->hasModifiedRecords(); + } + + /** + * Indicate if any records have been modified. + * + * @param bool $value + * @return void + * @static + */ + public static function recordsHaveBeenModified($value = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->recordsHaveBeenModified($value); + } + + /** + * Set the record modification state. + * + * @param bool $value + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setRecordModificationState($value) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setRecordModificationState($value); + } + + /** + * Reset the record modification state. + * + * @return void + * @static + */ + public static function forgetRecordModificationState() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->forgetRecordModificationState(); + } + + /** + * Indicate that the connection should use the write PDO connection for reads. + * + * @param bool $value + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function useWriteConnectionWhenReading($value = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->useWriteConnectionWhenReading($value); + } + + /** + * Get the current PDO connection. + * + * @return \PDO + * @static + */ + public static function getPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getPdo(); + } + + /** + * Get the current PDO connection parameter without executing any reconnect logic. + * + * @return \PDO|\Closure|null + * @static + */ + public static function getRawPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getRawPdo(); + } + + /** + * Get the current PDO connection used for reading. + * + * @return \PDO + * @static + */ + public static function getReadPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getReadPdo(); + } + + /** + * Get the current read PDO connection parameter without executing any reconnect logic. + * + * @return \PDO|\Closure|null + * @static + */ + public static function getRawReadPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getRawReadPdo(); + } + + /** + * Set the PDO connection. + * + * @param \PDO|\Closure|null $pdo + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setPdo($pdo) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setPdo($pdo); + } + + /** + * Set the PDO connection used for reading. + * + * @param \PDO|\Closure|null $pdo + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setReadPdo($pdo) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setReadPdo($pdo); + } + + /** + * Get the database connection name. + * + * @return string|null + * @static + */ + public static function getName() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getName(); + } + + /** + * Get the database connection full name. + * + * @return string|null + * @static + */ + public static function getNameWithReadWriteType() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getNameWithReadWriteType(); + } + + /** + * Get an option from the configuration options. + * + * @param string|null $option + * @return mixed + * @static + */ + public static function getConfig($option = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getConfig($option); + } + + /** + * Get the PDO driver name. + * + * @return string + * @static + */ + public static function getDriverName() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getDriverName(); + } + + /** + * Get the query grammar used by the connection. + * + * @return \Illuminate\Database\Query\Grammars\Grammar + * @static + */ + public static function getQueryGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getQueryGrammar(); + } + + /** + * Set the query grammar used by the connection. + * + * @param \Illuminate\Database\Query\Grammars\Grammar $grammar + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setQueryGrammar($grammar) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setQueryGrammar($grammar); + } + + /** + * Get the schema grammar used by the connection. + * + * @return \Illuminate\Database\Schema\Grammars\Grammar + * @static + */ + public static function getSchemaGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getSchemaGrammar(); + } + + /** + * Set the schema grammar used by the connection. + * + * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setSchemaGrammar($grammar) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setSchemaGrammar($grammar); + } + + /** + * Get the query post processor used by the connection. + * + * @return \Illuminate\Database\Query\Processors\Processor + * @static + */ + public static function getPostProcessor() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getPostProcessor(); + } + + /** + * Set the query post processor used by the connection. + * + * @param \Illuminate\Database\Query\Processors\Processor $processor + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setPostProcessor($processor) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setPostProcessor($processor); + } + + /** + * Get the event dispatcher used by the connection. + * + * @return \Illuminate\Contracts\Events\Dispatcher + * @static + */ + public static function getEventDispatcher() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getEventDispatcher(); + } + + /** + * Set the event dispatcher instance on the connection. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setEventDispatcher($events) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setEventDispatcher($events); + } + + /** + * Unset the event dispatcher for this connection. + * + * @return void + * @static + */ + public static function unsetEventDispatcher() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->unsetEventDispatcher(); + } + + /** + * Set the transaction manager instance on the connection. + * + * @param \Illuminate\Database\DatabaseTransactionsManager $manager + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setTransactionManager($manager) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setTransactionManager($manager); + } + + /** + * Unset the transaction manager for this connection. + * + * @return void + * @static + */ + public static function unsetTransactionManager() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->unsetTransactionManager(); + } + + /** + * Determine if the connection is in a "dry run". + * + * @return bool + * @static + */ + public static function pretending() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->pretending(); + } + + /** + * Get the connection query log. + * + * @return array + * @static + */ + public static function getQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getQueryLog(); + } + + /** + * Get the connection query log with embedded bindings. + * + * @return array + * @static + */ + public static function getRawQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getRawQueryLog(); + } + + /** + * Clear the query log. + * + * @return void + * @static + */ + public static function flushQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->flushQueryLog(); + } + + /** + * Enable the query log on the connection. + * + * @return void + * @static + */ + public static function enableQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->enableQueryLog(); + } + + /** + * Disable the query log on the connection. + * + * @return void + * @static + */ + public static function disableQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->disableQueryLog(); + } + + /** + * Determine whether we're logging queries. + * + * @return bool + * @static + */ + public static function logging() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->logging(); + } + + /** + * Get the name of the connected database. + * + * @return string + * @static + */ + public static function getDatabaseName() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getDatabaseName(); + } + + /** + * Set the name of the connected database. + * + * @param string $database + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setDatabaseName($database) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setDatabaseName($database); + } + + /** + * Set the read / write type of the connection. + * + * @param string|null $readWriteType + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setReadWriteType($readWriteType) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setReadWriteType($readWriteType); + } + + /** + * Get the table prefix for the connection. + * + * @return string + * @static + */ + public static function getTablePrefix() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getTablePrefix(); + } + + /** + * Set the table prefix in use by the connection. + * + * @param string $prefix + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setTablePrefix($prefix) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setTablePrefix($prefix); + } + + /** + * Execute the given callback without table prefix. + * + * @param \Closure $callback + * @return mixed + * @static + */ + public static function withoutTablePrefix($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->withoutTablePrefix($callback); + } + + /** + * Register a connection resolver. + * + * @param string $driver + * @param \Closure $callback + * @return void + * @static + */ + public static function resolverFor($driver, $callback) + { + //Method inherited from \Illuminate\Database\Connection + \Illuminate\Database\MySqlConnection::resolverFor($driver, $callback); + } + + /** + * Get the connection resolver for the given driver. + * + * @param string $driver + * @return \Closure|null + * @static + */ + public static function getResolver($driver) + { + //Method inherited from \Illuminate\Database\Connection + return \Illuminate\Database\MySqlConnection::getResolver($driver); + } + + /** + * + * + * @template TReturn of mixed + * + * Execute a Closure within a transaction. + * @param (\Closure(static): TReturn) $callback + * @param int $attempts + * @return TReturn + * @throws \Throwable + * @static + */ + public static function transaction($callback, $attempts = 1) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->transaction($callback, $attempts); + } + + /** + * Start a new database transaction. + * + * @return void + * @throws \Throwable + * @static + */ + public static function beginTransaction() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->beginTransaction(); + } + + /** + * Commit the active database transaction. + * + * @return void + * @throws \Throwable + * @static + */ + public static function commit() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->commit(); + } + + /** + * Rollback the active database transaction. + * + * @param int|null $toLevel + * @return void + * @throws \Throwable + * @static + */ + public static function rollBack($toLevel = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->rollBack($toLevel); + } + + /** + * Get the number of active transactions. + * + * @return int + * @static + */ + public static function transactionLevel() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->transactionLevel(); + } + + /** + * Execute the callback after a transaction commits. + * + * @param callable $callback + * @return void + * @throws \RuntimeException + * @static + */ + public static function afterCommit($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->afterCommit($callback); + } + + } + /** + * + * + * @see \Illuminate\Events\Dispatcher + * @see \Illuminate\Support\Testing\Fakes\EventFake + */ + class Event { + /** + * Register an event listener with the dispatcher. + * + * @param \Illuminate\Events\Queued\Closure|callable|array|class-string|string $events + * @param \Illuminate\Events\Queued\Closure|callable|array|class-string|null $listener + * @return void + * @static + */ + public static function listen($events, $listener = null) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->listen($events, $listener); + } + + /** + * Determine if a given event has listeners. + * + * @param string $eventName + * @return bool + * @static + */ + public static function hasListeners($eventName) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->hasListeners($eventName); + } + + /** + * Determine if the given event has any wildcard listeners. + * + * @param string $eventName + * @return bool + * @static + */ + public static function hasWildcardListeners($eventName) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->hasWildcardListeners($eventName); + } + + /** + * Register an event and payload to be fired later. + * + * @param string $event + * @param object|array $payload + * @return void + * @static + */ + public static function push($event, $payload = []) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->push($event, $payload); + } + + /** + * Flush a set of pushed events. + * + * @param string $event + * @return void + * @static + */ + public static function flush($event) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->flush($event); + } + + /** + * Register an event subscriber with the dispatcher. + * + * @param object|string $subscriber + * @return void + * @static + */ + public static function subscribe($subscriber) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->subscribe($subscriber); + } + + /** + * Fire an event until the first non-null response is returned. + * + * @param string|object $event + * @param mixed $payload + * @return mixed + * @static + */ + public static function until($event, $payload = []) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->until($event, $payload); + } + + /** + * Fire an event and call the listeners. + * + * @param string|object $event + * @param mixed $payload + * @param bool $halt + * @return array|null + * @static + */ + public static function dispatch($event, $payload = [], $halt = false) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->dispatch($event, $payload, $halt); + } + + /** + * Get all of the listeners for a given event name. + * + * @param string $eventName + * @return array + * @static + */ + public static function getListeners($eventName) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->getListeners($eventName); + } + + /** + * Register an event listener with the dispatcher. + * + * @param \Closure|string|array $listener + * @param bool $wildcard + * @return \Closure + * @static + */ + public static function makeListener($listener, $wildcard = false) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->makeListener($listener, $wildcard); + } + + /** + * Create a class based listener using the IoC container. + * + * @param string $listener + * @param bool $wildcard + * @return \Closure + * @static + */ + public static function createClassListener($listener, $wildcard = false) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->createClassListener($listener, $wildcard); + } + + /** + * Remove a set of listeners from the dispatcher. + * + * @param string $event + * @return void + * @static + */ + public static function forget($event) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->forget($event); + } + + /** + * Forget all of the pushed listeners. + * + * @return void + * @static + */ + public static function forgetPushed() + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->forgetPushed(); + } + + /** + * Set the queue resolver implementation. + * + * @param callable $resolver + * @return \Illuminate\Events\Dispatcher + * @static + */ + public static function setQueueResolver($resolver) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->setQueueResolver($resolver); + } + + /** + * Set the database transaction manager resolver implementation. + * + * @param callable $resolver + * @return \Illuminate\Events\Dispatcher + * @static + */ + public static function setTransactionManagerResolver($resolver) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->setTransactionManagerResolver($resolver); + } + + /** + * Gets the raw, unprepared listeners. + * + * @return array + * @static + */ + public static function getRawListeners() + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->getRawListeners(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Events\Dispatcher::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Events\Dispatcher::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Events\Dispatcher::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Events\Dispatcher::flushMacros(); + } + + /** + * Specify the events that should be dispatched instead of faked. + * + * @param array|string $eventsToDispatch + * @return \Illuminate\Support\Testing\Fakes\EventFake + * @static + */ + public static function except($eventsToDispatch) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->except($eventsToDispatch); + } + + /** + * Assert if an event has a listener attached to it. + * + * @param string $expectedEvent + * @param string|array $expectedListener + * @return void + * @static + */ + public static function assertListening($expectedEvent, $expectedListener) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertListening($expectedEvent, $expectedListener); + } + + /** + * Assert if an event was dispatched based on a truth-test callback. + * + * @param string|\Closure $event + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatched($event, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertDispatched($event, $callback); + } + + /** + * Assert if an event was dispatched a number of times. + * + * @param string $event + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedTimes($event, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertDispatchedTimes($event, $times); + } + + /** + * Determine if an event was dispatched based on a truth-test callback. + * + * @param string|\Closure $event + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatched($event, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertNotDispatched($event, $callback); + } + + /** + * Assert that no events were dispatched. + * + * @return void + * @static + */ + public static function assertNothingDispatched() + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertNothingDispatched(); + } + + /** + * Get all of the events matching a truth-test callback. + * + * @param string $event + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatched($event, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->dispatched($event, $callback); + } + + /** + * Determine if the given event has been dispatched. + * + * @param string $event + * @return bool + * @static + */ + public static function hasDispatched($event) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->hasDispatched($event); + } + + /** + * Get the events that have been dispatched. + * + * @return array + * @static + */ + public static function dispatchedEvents() + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->dispatchedEvents(); + } + + } + /** + * + * + * @see \Illuminate\Filesystem\Filesystem + */ + class File { + /** + * Determine if a file or directory exists. + * + * @param string $path + * @return bool + * @static + */ + public static function exists($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->exists($path); + } + + /** + * Determine if a file or directory is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function missing($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->missing($path); + } + + /** + * Get the contents of a file. + * + * @param string $path + * @param bool $lock + * @return string + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function get($path, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->get($path, $lock); + } + + /** + * Get the contents of a file as decoded JSON. + * + * @param string $path + * @param int $flags + * @param bool $lock + * @return array + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function json($path, $flags = 0, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->json($path, $flags, $lock); + } + + /** + * Get contents of a file with shared access. + * + * @param string $path + * @return string + * @static + */ + public static function sharedGet($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->sharedGet($path); + } + + /** + * Get the returned value of a file. + * + * @param string $path + * @param array $data + * @return mixed + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function getRequire($path, $data = []) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->getRequire($path, $data); + } + + /** + * Require the given file once. + * + * @param string $path + * @param array $data + * @return mixed + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function requireOnce($path, $data = []) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->requireOnce($path, $data); + } + + /** + * Get the contents of a file one line at a time. + * + * @param string $path + * @return \Illuminate\Support\LazyCollection + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function lines($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->lines($path); + } + + /** + * Get the hash of the file at the given path. + * + * @param string $path + * @param string $algorithm + * @return string|false + * @static + */ + public static function hash($path, $algorithm = 'md5') + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->hash($path, $algorithm); + } + + /** + * Write the contents of a file. + * + * @param string $path + * @param string $contents + * @param bool $lock + * @return int|bool + * @static + */ + public static function put($path, $contents, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->put($path, $contents, $lock); + } + + /** + * Write the contents of a file, replacing it atomically if it already exists. + * + * @param string $path + * @param string $content + * @param int|null $mode + * @return void + * @static + */ + public static function replace($path, $content, $mode = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->replace($path, $content, $mode); + } + + /** + * Replace a given string within a given file. + * + * @param array|string $search + * @param array|string $replace + * @param string $path + * @return void + * @static + */ + public static function replaceInFile($search, $replace, $path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->replaceInFile($search, $replace, $path); + } + + /** + * Prepend to a file. + * + * @param string $path + * @param string $data + * @return int + * @static + */ + public static function prepend($path, $data) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->prepend($path, $data); + } + + /** + * Append to a file. + * + * @param string $path + * @param string $data + * @param bool $lock + * @return int + * @static + */ + public static function append($path, $data, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->append($path, $data, $lock); + } + + /** + * Get or set UNIX mode of a file or directory. + * + * @param string $path + * @param int|null $mode + * @return mixed + * @static + */ + public static function chmod($path, $mode = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->chmod($path, $mode); + } + + /** + * Delete the file at a given path. + * + * @param string|array $paths + * @return bool + * @static + */ + public static function delete($paths) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->delete($paths); + } + + /** + * Move a file to a new location. + * + * @param string $path + * @param string $target + * @return bool + * @static + */ + public static function move($path, $target) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->move($path, $target); + } + + /** + * Copy a file to a new location. + * + * @param string $path + * @param string $target + * @return bool + * @static + */ + public static function copy($path, $target) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->copy($path, $target); + } + + /** + * Create a symlink to the target file or directory. On Windows, a hard link is created if the target is a file. + * + * @param string $target + * @param string $link + * @return bool|null + * @static + */ + public static function link($target, $link) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->link($target, $link); + } + + /** + * Create a relative symlink to the target file or directory. + * + * @param string $target + * @param string $link + * @return void + * @throws \RuntimeException + * @static + */ + public static function relativeLink($target, $link) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->relativeLink($target, $link); + } + + /** + * Extract the file name from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function name($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->name($path); + } + + /** + * Extract the trailing name component from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function basename($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->basename($path); + } + + /** + * Extract the parent directory from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function dirname($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->dirname($path); + } + + /** + * Extract the file extension from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function extension($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->extension($path); + } + + /** + * Guess the file extension from the mime-type of a given file. + * + * @param string $path + * @return string|null + * @throws \RuntimeException + * @static + */ + public static function guessExtension($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->guessExtension($path); + } + + /** + * Get the file type of a given file. + * + * @param string $path + * @return string + * @static + */ + public static function type($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->type($path); + } + + /** + * Get the mime-type of a given file. + * + * @param string $path + * @return string|false + * @static + */ + public static function mimeType($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->mimeType($path); + } + + /** + * Get the file size of a given file. + * + * @param string $path + * @return int + * @static + */ + public static function size($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->size($path); + } + + /** + * Get the file's last modification time. + * + * @param string $path + * @return int + * @static + */ + public static function lastModified($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->lastModified($path); + } + + /** + * Determine if the given path is a directory. + * + * @param string $directory + * @return bool + * @static + */ + public static function isDirectory($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isDirectory($directory); + } + + /** + * Determine if the given path is a directory that does not contain any other files or directories. + * + * @param string $directory + * @param bool $ignoreDotFiles + * @return bool + * @static + */ + public static function isEmptyDirectory($directory, $ignoreDotFiles = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isEmptyDirectory($directory, $ignoreDotFiles); + } + + /** + * Determine if the given path is readable. + * + * @param string $path + * @return bool + * @static + */ + public static function isReadable($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isReadable($path); + } + + /** + * Determine if the given path is writable. + * + * @param string $path + * @return bool + * @static + */ + public static function isWritable($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isWritable($path); + } + + /** + * Determine if two files are the same by comparing their hashes. + * + * @param string $firstFile + * @param string $secondFile + * @return bool + * @static + */ + public static function hasSameHash($firstFile, $secondFile) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->hasSameHash($firstFile, $secondFile); + } + + /** + * Determine if the given path is a file. + * + * @param string $file + * @return bool + * @static + */ + public static function isFile($file) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isFile($file); + } + + /** + * Find path names matching a given pattern. + * + * @param string $pattern + * @param int $flags + * @return array + * @static + */ + public static function glob($pattern, $flags = 0) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->glob($pattern, $flags); + } + + /** + * Get an array of all files in a directory. + * + * @param string $directory + * @param bool $hidden + * @return \Symfony\Component\Finder\SplFileInfo[] + * @static + */ + public static function files($directory, $hidden = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->files($directory, $hidden); + } + + /** + * Get all of the files from the given directory (recursive). + * + * @param string $directory + * @param bool $hidden + * @return \Symfony\Component\Finder\SplFileInfo[] + * @static + */ + public static function allFiles($directory, $hidden = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->allFiles($directory, $hidden); + } + + /** + * Get all of the directories within a given directory. + * + * @param string $directory + * @return array + * @static + */ + public static function directories($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->directories($directory); + } + + /** + * Ensure a directory exists. + * + * @param string $path + * @param int $mode + * @param bool $recursive + * @return void + * @static + */ + public static function ensureDirectoryExists($path, $mode = 493, $recursive = true) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->ensureDirectoryExists($path, $mode, $recursive); + } + + /** + * Create a directory. + * + * @param string $path + * @param int $mode + * @param bool $recursive + * @param bool $force + * @return bool + * @static + */ + public static function makeDirectory($path, $mode = 493, $recursive = false, $force = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->makeDirectory($path, $mode, $recursive, $force); + } + + /** + * Move a directory. + * + * @param string $from + * @param string $to + * @param bool $overwrite + * @return bool + * @static + */ + public static function moveDirectory($from, $to, $overwrite = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->moveDirectory($from, $to, $overwrite); + } + + /** + * Copy a directory from one location to another. + * + * @param string $directory + * @param string $destination + * @param int|null $options + * @return bool + * @static + */ + public static function copyDirectory($directory, $destination, $options = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->copyDirectory($directory, $destination, $options); + } + + /** + * Recursively delete a directory. + * + * The directory itself may be optionally preserved. + * + * @param string $directory + * @param bool $preserve + * @return bool + * @static + */ + public static function deleteDirectory($directory, $preserve = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->deleteDirectory($directory, $preserve); + } + + /** + * Remove all of the directories within a given directory. + * + * @param string $directory + * @return bool + * @static + */ + public static function deleteDirectories($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->deleteDirectories($directory); + } + + /** + * Empty the specified directory of all files and folders. + * + * @param string $directory + * @return bool + * @static + */ + public static function cleanDirectory($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->cleanDirectory($directory); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Filesystem\Filesystem::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Filesystem\Filesystem::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Filesystem\Filesystem::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Filesystem\Filesystem::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Auth\Access\Gate + */ + class Gate { + /** + * Determine if a given ability has been defined. + * + * @param string|array $ability + * @return bool + * @static + */ + public static function has($ability) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->has($ability); + } + + /** + * Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is false. + * + * @param \Illuminate\Auth\Access\Response|\Closure|bool $condition + * @param string|null $message + * @param string|null $code + * @return \Illuminate\Auth\Access\Response + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function allowIf($condition, $message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->allowIf($condition, $message, $code); + } + + /** + * Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is true. + * + * @param \Illuminate\Auth\Access\Response|\Closure|bool $condition + * @param string|null $message + * @param string|null $code + * @return \Illuminate\Auth\Access\Response + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function denyIf($condition, $message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denyIf($condition, $message, $code); + } + + /** + * Define a new ability. + * + * @param \UnitEnum|string $ability + * @param callable|array|string $callback + * @return \Illuminate\Auth\Access\Gate + * @throws \InvalidArgumentException + * @static + */ + public static function define($ability, $callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->define($ability, $callback); + } + + /** + * Define abilities for a resource. + * + * @param string $name + * @param string $class + * @param array|null $abilities + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function resource($name, $class, $abilities = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->resource($name, $class, $abilities); + } + + /** + * Define a policy class for a given class type. + * + * @param string $class + * @param string $policy + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function policy($class, $policy) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->policy($class, $policy); + } + + /** + * Register a callback to run before all Gate checks. + * + * @param callable $callback + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function before($callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->before($callback); + } + + /** + * Register a callback to run after all Gate checks. + * + * @param callable $callback + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function after($callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->after($callback); + } + + /** + * Determine if all of the given abilities should be granted for the current user. + * + * @param iterable|\UnitEnum|string $ability + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function allows($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->allows($ability, $arguments); + } + + /** + * Determine if any of the given abilities should be denied for the current user. + * + * @param iterable|\UnitEnum|string $ability + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function denies($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denies($ability, $arguments); + } + + /** + * Determine if all of the given abilities should be granted for the current user. + * + * @param iterable|\UnitEnum|string $abilities + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function check($abilities, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->check($abilities, $arguments); + } + + /** + * Determine if any one of the given abilities should be granted for the current user. + * + * @param iterable|\UnitEnum|string $abilities + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function any($abilities, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->any($abilities, $arguments); + } + + /** + * Determine if all of the given abilities should be denied for the current user. + * + * @param iterable|\UnitEnum|string $abilities + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function none($abilities, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->none($abilities, $arguments); + } + + /** + * Determine if the given ability should be granted for the current user. + * + * @param \UnitEnum|string $ability + * @param array|mixed $arguments + * @return \Illuminate\Auth\Access\Response + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function authorize($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->authorize($ability, $arguments); + } + + /** + * Inspect the user for the given ability. + * + * @param \UnitEnum|string $ability + * @param array|mixed $arguments + * @return \Illuminate\Auth\Access\Response + * @static + */ + public static function inspect($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->inspect($ability, $arguments); + } + + /** + * Get the raw result from the authorization callback. + * + * @param string $ability + * @param array|mixed $arguments + * @return mixed + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function raw($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->raw($ability, $arguments); + } + + /** + * Get a policy instance for a given class. + * + * @param object|string $class + * @return mixed + * @static + */ + public static function getPolicyFor($class) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->getPolicyFor($class); + } + + /** + * Specify a callback to be used to guess policy names. + * + * @param callable $callback + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function guessPolicyNamesUsing($callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->guessPolicyNamesUsing($callback); + } + + /** + * Build a policy class instance of the given type. + * + * @param object|string $class + * @return mixed + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @static + */ + public static function resolvePolicy($class) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->resolvePolicy($class); + } + + /** + * Get a gate instance for the given user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable|mixed $user + * @return static + * @static + */ + public static function forUser($user) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->forUser($user); + } + + /** + * Get all of the defined abilities. + * + * @return array + * @static + */ + public static function abilities() + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->abilities(); + } + + /** + * Get all of the defined policies. + * + * @return array + * @static + */ + public static function policies() + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->policies(); + } + + /** + * Set the default denial response for gates and policies. + * + * @param \Illuminate\Auth\Access\Response $response + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function defaultDenialResponse($response) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->defaultDenialResponse($response); + } + + /** + * Set the container instance used by the gate. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->setContainer($container); + } + + /** + * Deny with a HTTP status code. + * + * @param int $status + * @param string|null $message + * @param int|null $code + * @return \Illuminate\Auth\Access\Response + * @static + */ + public static function denyWithStatus($status, $message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denyWithStatus($status, $message, $code); + } + + /** + * Deny with a 404 HTTP status code. + * + * @param string|null $message + * @param int|null $code + * @return \Illuminate\Auth\Access\Response + * @static + */ + public static function denyAsNotFound($message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denyAsNotFound($message, $code); + } + + } + /** + * + * + * @see \Illuminate\Hashing\HashManager + * @see \Illuminate\Hashing\AbstractHasher + */ + class Hash { + /** + * Create an instance of the Bcrypt hash Driver. + * + * @return \Illuminate\Hashing\BcryptHasher + * @static + */ + public static function createBcryptDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->createBcryptDriver(); + } + + /** + * Create an instance of the Argon2i hash Driver. + * + * @return \Illuminate\Hashing\ArgonHasher + * @static + */ + public static function createArgonDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->createArgonDriver(); + } + + /** + * Create an instance of the Argon2id hash Driver. + * + * @return \Illuminate\Hashing\Argon2IdHasher + * @static + */ + public static function createArgon2idDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->createArgon2idDriver(); + } + + /** + * Get information about the given hashed value. + * + * @param string $hashedValue + * @return array + * @static + */ + public static function info($hashedValue) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->info($hashedValue); + } + + /** + * Hash the given value. + * + * @param string $value + * @param array $options + * @return string + * @static + */ + public static function make($value, $options = []) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->make($value, $options); + } + + /** + * Check the given plain value against a hash. + * + * @param string $value + * @param string $hashedValue + * @param array $options + * @return bool + * @static + */ + public static function check($value, $hashedValue, $options = []) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->check($value, $hashedValue, $options); + } + + /** + * Check if the given hash has been hashed using the given options. + * + * @param string $hashedValue + * @param array $options + * @return bool + * @static + */ + public static function needsRehash($hashedValue, $options = []) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->needsRehash($hashedValue, $options); + } + + /** + * Determine if a given string is already hashed. + * + * @param string $value + * @return bool + * @static + */ + public static function isHashed($value) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->isHashed($value); + } + + /** + * Get the default driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Verifies that the configuration is less than or equal to what is configured. + * + * @param array $value + * @return bool + * @internal + * @static + */ + public static function verifyConfiguration($value) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->verifyConfiguration($value); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function driver($driver = null) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->driver($driver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Hashing\HashManager + * @static + */ + public static function extend($driver, $callback) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get all of the created "drivers". + * + * @return array + * @static + */ + public static function getDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->getDrivers(); + } + + /** + * Get the container instance used by the manager. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the manager. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Hashing\HashManager + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->setContainer($container); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Hashing\HashManager + * @static + */ + public static function forgetDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->forgetDrivers(); + } + + } + /** + * + * + * @method static \Illuminate\Http\Client\PendingRequest baseUrl(string $url) + * @method static \Illuminate\Http\Client\PendingRequest withBody(\Psr\Http\Message\StreamInterface|string $content, string $contentType = 'application/json') + * @method static \Illuminate\Http\Client\PendingRequest asJson() + * @method static \Illuminate\Http\Client\PendingRequest asForm() + * @method static \Illuminate\Http\Client\PendingRequest attach(string|array $name, string|resource $contents = '', string|null $filename = null, array $headers = []) + * @method static \Illuminate\Http\Client\PendingRequest asMultipart() + * @method static \Illuminate\Http\Client\PendingRequest bodyFormat(string $format) + * @method static \Illuminate\Http\Client\PendingRequest withQueryParameters(array $parameters) + * @method static \Illuminate\Http\Client\PendingRequest contentType(string $contentType) + * @method static \Illuminate\Http\Client\PendingRequest acceptJson() + * @method static \Illuminate\Http\Client\PendingRequest accept(string $contentType) + * @method static \Illuminate\Http\Client\PendingRequest withHeaders(array $headers) + * @method static \Illuminate\Http\Client\PendingRequest withHeader(string $name, mixed $value) + * @method static \Illuminate\Http\Client\PendingRequest replaceHeaders(array $headers) + * @method static \Illuminate\Http\Client\PendingRequest withBasicAuth(string $username, string $password) + * @method static \Illuminate\Http\Client\PendingRequest withDigestAuth(string $username, string $password) + * @method static \Illuminate\Http\Client\PendingRequest withToken(string $token, string $type = 'Bearer') + * @method static \Illuminate\Http\Client\PendingRequest withUserAgent(string|bool $userAgent) + * @method static \Illuminate\Http\Client\PendingRequest withUrlParameters(array $parameters = []) + * @method static \Illuminate\Http\Client\PendingRequest withCookies(array $cookies, string $domain) + * @method static \Illuminate\Http\Client\PendingRequest maxRedirects(int $max) + * @method static \Illuminate\Http\Client\PendingRequest withoutRedirecting() + * @method static \Illuminate\Http\Client\PendingRequest withoutVerifying() + * @method static \Illuminate\Http\Client\PendingRequest sink(string|resource $to) + * @method static \Illuminate\Http\Client\PendingRequest timeout(int|float $seconds) + * @method static \Illuminate\Http\Client\PendingRequest connectTimeout(int|float $seconds) + * @method static \Illuminate\Http\Client\PendingRequest retry(array|int $times, \Closure|int $sleepMilliseconds = 0, callable|null $when = null, bool $throw = true) + * @method static \Illuminate\Http\Client\PendingRequest withOptions(array $options) + * @method static \Illuminate\Http\Client\PendingRequest withMiddleware(callable $middleware) + * @method static \Illuminate\Http\Client\PendingRequest withRequestMiddleware(callable $middleware) + * @method static \Illuminate\Http\Client\PendingRequest withResponseMiddleware(callable $middleware) + * @method static \Illuminate\Http\Client\PendingRequest beforeSending(callable $callback) + * @method static \Illuminate\Http\Client\PendingRequest throw(callable|null $callback = null) + * @method static \Illuminate\Http\Client\PendingRequest throwIf(callable|bool $condition) + * @method static \Illuminate\Http\Client\PendingRequest throwUnless(callable|bool $condition) + * @method static \Illuminate\Http\Client\PendingRequest dump() + * @method static \Illuminate\Http\Client\PendingRequest dd() + * @method static \Illuminate\Http\Client\Response get(string $url, array|string|null $query = null) + * @method static \Illuminate\Http\Client\Response head(string $url, array|string|null $query = null) + * @method static \Illuminate\Http\Client\Response post(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response patch(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response put(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response delete(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static array pool(callable $callback) + * @method static \Illuminate\Http\Client\Response send(string $method, string $url, array $options = []) + * @method static \GuzzleHttp\Client buildClient() + * @method static \GuzzleHttp\Client createClient(\GuzzleHttp\HandlerStack $handlerStack) + * @method static \GuzzleHttp\HandlerStack buildHandlerStack() + * @method static \GuzzleHttp\HandlerStack pushHandlers(\GuzzleHttp\HandlerStack $handlerStack) + * @method static \Closure buildBeforeSendingHandler() + * @method static \Closure buildRecorderHandler() + * @method static \Closure buildStubHandler() + * @method static \GuzzleHttp\Psr7\RequestInterface runBeforeSendingCallbacks(\GuzzleHttp\Psr7\RequestInterface $request, array $options) + * @method static array mergeOptions(array ...$options) + * @method static \Illuminate\Http\Client\PendingRequest stub(callable $callback) + * @method static \Illuminate\Http\Client\PendingRequest async(bool $async = true) + * @method static \GuzzleHttp\Promise\PromiseInterface|null getPromise() + * @method static \Illuminate\Http\Client\PendingRequest setClient(\GuzzleHttp\Client $client) + * @method static \Illuminate\Http\Client\PendingRequest setHandler(callable $handler) + * @method static array getOptions() + * @method static \Illuminate\Http\Client\PendingRequest|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @method static \Illuminate\Http\Client\PendingRequest|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @see \Illuminate\Http\Client\Factory + */ + class Http { + /** + * Add middleware to apply to every request. + * + * @param callable $middleware + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalMiddleware($middleware) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalMiddleware($middleware); + } + + /** + * Add request middleware to apply to every request. + * + * @param callable $middleware + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalRequestMiddleware($middleware) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalRequestMiddleware($middleware); + } + + /** + * Add response middleware to apply to every request. + * + * @param callable $middleware + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalResponseMiddleware($middleware) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalResponseMiddleware($middleware); + } + + /** + * Set the options to apply to every request. + * + * @param \Closure|array $options + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalOptions($options) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalOptions($options); + } + + /** + * Create a new response instance for use during stubbing. + * + * @param array|string|null $body + * @param int $status + * @param array $headers + * @return \GuzzleHttp\Promise\PromiseInterface + * @static + */ + public static function response($body = null, $status = 200, $headers = []) + { + return \Illuminate\Http\Client\Factory::response($body, $status, $headers); + } + + /** + * Create a new connection exception for use during stubbing. + * + * @param string|null $message + * @return \GuzzleHttp\Promise\PromiseInterface + * @static + */ + public static function failedConnection($message = null) + { + return \Illuminate\Http\Client\Factory::failedConnection($message); + } + + /** + * Get an invokable object that returns a sequence of responses in order for use during stubbing. + * + * @param array $responses + * @return \Illuminate\Http\Client\ResponseSequence + * @static + */ + public static function sequence($responses = []) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->sequence($responses); + } + + /** + * Register a stub callable that will intercept requests and be able to return stub responses. + * + * @param callable|array|null $callback + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function fake($callback = null) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->fake($callback); + } + + /** + * Register a response sequence for the given URL pattern. + * + * @param string $url + * @return \Illuminate\Http\Client\ResponseSequence + * @static + */ + public static function fakeSequence($url = '*') + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->fakeSequence($url); + } + + /** + * Stub the given URL using the given callback. + * + * @param string $url + * @param \Illuminate\Http\Client\Response|\GuzzleHttp\Promise\PromiseInterface|callable|int|string|array $callback + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function stubUrl($url, $callback) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->stubUrl($url, $callback); + } + + /** + * Indicate that an exception should be thrown if any request is not faked. + * + * @param bool $prevent + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function preventStrayRequests($prevent = true) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->preventStrayRequests($prevent); + } + + /** + * Determine if stray requests are being prevented. + * + * @return bool + * @static + */ + public static function preventingStrayRequests() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->preventingStrayRequests(); + } + + /** + * Indicate that an exception should not be thrown if any request is not faked. + * + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function allowStrayRequests() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->allowStrayRequests(); + } + + /** + * Begin recording request / response pairs. + * + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function record() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->record(); + } + + /** + * Record a request response pair. + * + * @param \Illuminate\Http\Client\Request $request + * @param \Illuminate\Http\Client\Response|null $response + * @return void + * @static + */ + public static function recordRequestResponsePair($request, $response) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->recordRequestResponsePair($request, $response); + } + + /** + * Assert that a request / response pair was recorded matching a given truth test. + * + * @param callable $callback + * @return void + * @static + */ + public static function assertSent($callback) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSent($callback); + } + + /** + * Assert that the given request was sent in the given order. + * + * @param array $callbacks + * @return void + * @static + */ + public static function assertSentInOrder($callbacks) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSentInOrder($callbacks); + } + + /** + * Assert that a request / response pair was not recorded matching a given truth test. + * + * @param callable $callback + * @return void + * @static + */ + public static function assertNotSent($callback) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertNotSent($callback); + } + + /** + * Assert that no request / response pair was recorded. + * + * @return void + * @static + */ + public static function assertNothingSent() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertNothingSent(); + } + + /** + * Assert how many requests have been recorded. + * + * @param int $count + * @return void + * @static + */ + public static function assertSentCount($count) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSentCount($count); + } + + /** + * Assert that every created response sequence is empty. + * + * @return void + * @static + */ + public static function assertSequencesAreEmpty() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSequencesAreEmpty(); + } + + /** + * Get a collection of the request / response pairs matching the given truth test. + * + * @param callable $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function recorded($callback = null) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->recorded($callback); + } + + /** + * Create a new pending request instance for this factory. + * + * @return \Illuminate\Http\Client\PendingRequest + * @static + */ + public static function createPendingRequest() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->createPendingRequest(); + } + + /** + * Get the current event dispatcher implementation. + * + * @return \Illuminate\Contracts\Events\Dispatcher|null + * @static + */ + public static function getDispatcher() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->getDispatcher(); + } + + /** + * Get the array of global middleware. + * + * @return array + * @static + */ + public static function getGlobalMiddleware() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->getGlobalMiddleware(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Http\Client\Factory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Http\Client\Factory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Http\Client\Factory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Http\Client\Factory::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Translation\Translator + */ + class Lang { + /** + * Determine if a translation exists for a given locale. + * + * @param string $key + * @param string|null $locale + * @return bool + * @static + */ + public static function hasForLocale($key, $locale = null) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->hasForLocale($key, $locale); + } + + /** + * Determine if a translation exists. + * + * @param string $key + * @param string|null $locale + * @param bool $fallback + * @return bool + * @static + */ + public static function has($key, $locale = null, $fallback = true) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->has($key, $locale, $fallback); + } + + /** + * Get the translation for the given key. + * + * @param string $key + * @param array $replace + * @param string|null $locale + * @param bool $fallback + * @return string|array + * @static + */ + public static function get($key, $replace = [], $locale = null, $fallback = true) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->get($key, $replace, $locale, $fallback); + } + + /** + * Get a translation according to an integer value. + * + * @param string $key + * @param \Countable|int|float|array $number + * @param array $replace + * @param string|null $locale + * @return string + * @static + */ + public static function choice($key, $number, $replace = [], $locale = null) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->choice($key, $number, $replace, $locale); + } + + /** + * Add translation lines to the given locale. + * + * @param array $lines + * @param string $locale + * @param string $namespace + * @return void + * @static + */ + public static function addLines($lines, $locale, $namespace = '*') + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addLines($lines, $locale, $namespace); + } + + /** + * Load the specified language group. + * + * @param string $namespace + * @param string $group + * @param string $locale + * @return void + * @static + */ + public static function load($namespace, $group, $locale) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->load($namespace, $group, $locale); + } + + /** + * Register a callback that is responsible for handling missing translation keys. + * + * @param callable|null $callback + * @return static + * @static + */ + public static function handleMissingKeysUsing($callback) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->handleMissingKeysUsing($callback); + } + + /** + * Add a new namespace to the loader. + * + * @param string $namespace + * @param string $hint + * @return void + * @static + */ + public static function addNamespace($namespace, $hint) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addNamespace($namespace, $hint); + } + + /** + * Add a new path to the loader. + * + * @param string $path + * @return void + * @static + */ + public static function addPath($path) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addPath($path); + } + + /** + * Add a new JSON path to the loader. + * + * @param string $path + * @return void + * @static + */ + public static function addJsonPath($path) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addJsonPath($path); + } + + /** + * Parse a key into namespace, group, and item. + * + * @param string $key + * @return array + * @static + */ + public static function parseKey($key) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->parseKey($key); + } + + /** + * Specify a callback that should be invoked to determined the applicable locale array. + * + * @param callable $callback + * @return void + * @static + */ + public static function determineLocalesUsing($callback) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->determineLocalesUsing($callback); + } + + /** + * Get the message selector instance. + * + * @return \Illuminate\Translation\MessageSelector + * @static + */ + public static function getSelector() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getSelector(); + } + + /** + * Set the message selector instance. + * + * @param \Illuminate\Translation\MessageSelector $selector + * @return void + * @static + */ + public static function setSelector($selector) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setSelector($selector); + } + + /** + * Get the language line loader implementation. + * + * @return \Illuminate\Contracts\Translation\Loader + * @static + */ + public static function getLoader() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getLoader(); + } + + /** + * Get the default locale being used. + * + * @return string + * @static + */ + public static function locale() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->locale(); + } + + /** + * Get the default locale being used. + * + * @return string + * @static + */ + public static function getLocale() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getLocale(); + } + + /** + * Set the default locale. + * + * @param string $locale + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function setLocale($locale) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setLocale($locale); + } + + /** + * Get the fallback locale being used. + * + * @return string + * @static + */ + public static function getFallback() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getFallback(); + } + + /** + * Set the fallback locale being used. + * + * @param string $fallback + * @return void + * @static + */ + public static function setFallback($fallback) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setFallback($fallback); + } + + /** + * Set the loaded translation groups. + * + * @param array $loaded + * @return void + * @static + */ + public static function setLoaded($loaded) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setLoaded($loaded); + } + + /** + * Add a handler to be executed in order to format a given class to a string during translation replacements. + * + * @param callable|string $class + * @param callable|null $handler + * @return void + * @static + */ + public static function stringable($class, $handler = null) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->stringable($class, $handler); + } + + /** + * Set the parsed value of a key. + * + * @param string $key + * @param array $parsed + * @return void + * @static + */ + public static function setParsedKey($key, $parsed) + { + //Method inherited from \Illuminate\Support\NamespacedItemResolver + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setParsedKey($key, $parsed); + } + + /** + * Flush the cache of parsed keys. + * + * @return void + * @static + */ + public static function flushParsedKeys() + { + //Method inherited from \Illuminate\Support\NamespacedItemResolver + /** @var \Illuminate\Translation\Translator $instance */ + $instance->flushParsedKeys(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Translation\Translator::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Translation\Translator::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Translation\Translator::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Translation\Translator::flushMacros(); + } + + } + /** + * + * + * @method static void write(string $level, \Illuminate\Contracts\Support\Arrayable|\Illuminate\Contracts\Support\Jsonable|\Illuminate\Support\Stringable|array|string $message, array $context = []) + * @method static \Illuminate\Log\Logger withContext(array $context = []) + * @method static void listen(\Closure $callback) + * @method static \Psr\Log\LoggerInterface getLogger() + * @method static \Illuminate\Contracts\Events\Dispatcher getEventDispatcher() + * @method static void setEventDispatcher(\Illuminate\Contracts\Events\Dispatcher $dispatcher) + * @method static \Illuminate\Log\Logger|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @method static \Illuminate\Log\Logger|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @see \Illuminate\Log\LogManager + */ + class Log { + /** + * Build an on-demand log channel. + * + * @param array $config + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->build($config); + } + + /** + * Create a new, on-demand aggregate logger instance. + * + * @param array $channels + * @param string|null $channel + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function stack($channels, $channel = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->stack($channels, $channel); + } + + /** + * Get a log channel instance. + * + * @param string|null $channel + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function channel($channel = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->channel($channel); + } + + /** + * Get a log driver instance. + * + * @param string|null $driver + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function driver($driver = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->driver($driver); + } + + /** + * Share context across channels and stacks. + * + * @param array $context + * @return \Illuminate\Log\LogManager + * @static + */ + public static function shareContext($context) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->shareContext($context); + } + + /** + * The context shared across channels and stacks. + * + * @return array + * @static + */ + public static function sharedContext() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->sharedContext(); + } + + /** + * Flush the log context on all currently resolved channels. + * + * @return \Illuminate\Log\LogManager + * @static + */ + public static function withoutContext() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->withoutContext(); + } + + /** + * Flush the shared context. + * + * @return \Illuminate\Log\LogManager + * @static + */ + public static function flushSharedContext() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->flushSharedContext(); + } + + /** + * Get the default log driver name. + * + * @return string|null + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default log driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @param-closure-this $this $callback + * @return \Illuminate\Log\LogManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Unset the given channel instance. + * + * @param string|null $driver + * @return void + * @static + */ + public static function forgetChannel($driver = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->forgetChannel($driver); + } + + /** + * Get all of the resolved log channels. + * + * @return array + * @static + */ + public static function getChannels() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->getChannels(); + } + + /** + * System is unusable. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function emergency($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->emergency($message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function alert($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->alert($message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function critical($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->critical($message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function error($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->error($message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function warning($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->warning($message, $context); + } + + /** + * Normal but significant events. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function notice($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->notice($message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function info($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->info($message, $context); + } + + /** + * Detailed debug information. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function debug($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->debug($message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function log($level, $message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->log($level, $message, $context); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Log\LogManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->setApplication($app); + } + + } + /** + * + * + * @method static void alwaysFrom(string $address, string|null $name = null) + * @method static void alwaysReplyTo(string $address, string|null $name = null) + * @method static void alwaysReturnPath(string $address) + * @method static void alwaysTo(string $address, string|null $name = null) + * @method static \Illuminate\Mail\SentMessage|null html(string $html, mixed $callback) + * @method static \Illuminate\Mail\SentMessage|null plain(string $view, array $data, mixed $callback) + * @method static string render(string|array $view, array $data = []) + * @method static mixed onQueue(\BackedEnum|string|null $queue, \Illuminate\Contracts\Mail\Mailable $view) + * @method static mixed queueOn(string $queue, \Illuminate\Contracts\Mail\Mailable $view) + * @method static mixed laterOn(string $queue, \DateTimeInterface|\DateInterval|int $delay, \Illuminate\Contracts\Mail\Mailable $view) + * @method static \Symfony\Component\Mailer\Transport\TransportInterface getSymfonyTransport() + * @method static \Illuminate\Contracts\View\Factory getViewFactory() + * @method static void setSymfonyTransport(\Symfony\Component\Mailer\Transport\TransportInterface $transport) + * @method static \Illuminate\Mail\Mailer setQueue(\Illuminate\Contracts\Queue\Factory $queue) + * @method static void macro(string $name, object|callable $macro) + * @method static void mixin(object $mixin, bool $replace = true) + * @method static bool hasMacro(string $name) + * @method static void flushMacros() + * @see \Illuminate\Mail\MailManager + * @see \Illuminate\Support\Testing\Fakes\MailFake + */ + class Mail { + /** + * Get a mailer instance by name. + * + * @param string|null $name + * @return \Illuminate\Contracts\Mail\Mailer + * @static + */ + public static function mailer($name = null) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->mailer($name); + } + + /** + * Get a mailer driver instance. + * + * @param string|null $driver + * @return \Illuminate\Mail\Mailer + * @static + */ + public static function driver($driver = null) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->driver($driver); + } + + /** + * Build a new mailer instance. + * + * @param array $config + * @return \Illuminate\Mail\Mailer + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->build($config); + } + + /** + * Create a new transport instance. + * + * @param array $config + * @return \Symfony\Component\Mailer\Transport\TransportInterface + * @throws \InvalidArgumentException + * @static + */ + public static function createSymfonyTransport($config) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->createSymfonyTransport($config); + } + + /** + * Get the default mail driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default mail driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Mail\MailManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Disconnect the given mailer and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Mail\MailManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom transport creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Mail\MailManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + * @static + */ + public static function getApplication() + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->getApplication(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Mail\MailManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->setApplication($app); + } + + /** + * Forget all of the resolved mailer instances. + * + * @return \Illuminate\Mail\MailManager + * @static + */ + public static function forgetMailers() + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->forgetMailers(); + } + + /** + * Assert if a mailable was sent based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|int|null $callback + * @return void + * @static + */ + public static function assertSent($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertSent($mailable, $callback); + } + + /** + * Determine if a mailable was not sent or queued to be sent based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotOutgoing($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNotOutgoing($mailable, $callback); + } + + /** + * Determine if a mailable was not sent based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|null $callback + * @return void + * @static + */ + public static function assertNotSent($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNotSent($mailable, $callback); + } + + /** + * Assert that no mailables were sent or queued to be sent. + * + * @return void + * @static + */ + public static function assertNothingOutgoing() + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNothingOutgoing(); + } + + /** + * Assert that no mailables were sent. + * + * @return void + * @static + */ + public static function assertNothingSent() + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNothingSent(); + } + + /** + * Assert if a mailable was queued based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|int|null $callback + * @return void + * @static + */ + public static function assertQueued($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertQueued($mailable, $callback); + } + + /** + * Determine if a mailable was not queued based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|null $callback + * @return void + * @static + */ + public static function assertNotQueued($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNotQueued($mailable, $callback); + } + + /** + * Assert that no mailables were queued. + * + * @return void + * @static + */ + public static function assertNothingQueued() + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNothingQueued(); + } + + /** + * Assert the total number of mailables that were sent. + * + * @param int $count + * @return void + * @static + */ + public static function assertSentCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertSentCount($count); + } + + /** + * Assert the total number of mailables that were queued. + * + * @param int $count + * @return void + * @static + */ + public static function assertQueuedCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertQueuedCount($count); + } + + /** + * Assert the total number of mailables that were sent or queued. + * + * @param int $count + * @return void + * @static + */ + public static function assertOutgoingCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertOutgoingCount($count); + } + + /** + * Get all of the mailables matching a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function sent($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->sent($mailable, $callback); + } + + /** + * Determine if the given mailable has been sent. + * + * @param string $mailable + * @return bool + * @static + */ + public static function hasSent($mailable) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->hasSent($mailable); + } + + /** + * Get all of the queued mailables matching a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function queued($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->queued($mailable, $callback); + } + + /** + * Determine if the given mailable has been queued. + * + * @param string $mailable + * @return bool + * @static + */ + public static function hasQueued($mailable) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->hasQueued($mailable); + } + + /** + * Begin the process of mailing a mailable class instance. + * + * @param mixed $users + * @return \Illuminate\Mail\PendingMail + * @static + */ + public static function to($users) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->to($users); + } + + /** + * Begin the process of mailing a mailable class instance. + * + * @param mixed $users + * @return \Illuminate\Mail\PendingMail + * @static + */ + public static function cc($users) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->cc($users); + } + + /** + * Begin the process of mailing a mailable class instance. + * + * @param mixed $users + * @return \Illuminate\Mail\PendingMail + * @static + */ + public static function bcc($users) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->bcc($users); + } + + /** + * Send a new message with only a raw text part. + * + * @param string $text + * @param \Closure|string $callback + * @return void + * @static + */ + public static function raw($text, $callback) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->raw($text, $callback); + } + + /** + * Send a new message using a view. + * + * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param array $data + * @param \Closure|string|null $callback + * @return mixed|void + * @static + */ + public static function send($view, $data = [], $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->send($view, $data, $callback); + } + + /** + * Send a new message synchronously using a view. + * + * @param \Illuminate\Contracts\Mail\Mailable|string|array $mailable + * @param array $data + * @param \Closure|string|null $callback + * @return void + * @static + */ + public static function sendNow($mailable, $data = [], $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->sendNow($mailable, $data, $callback); + } + + /** + * Queue a new message for sending. + * + * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param string|null $queue + * @return mixed + * @static + */ + public static function queue($view, $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->queue($view, $queue); + } + + /** + * Queue a new e-mail message for sending after (n) seconds. + * + * @param \DateTimeInterface|\DateInterval|int $delay + * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param string|null $queue + * @return mixed + * @static + */ + public static function later($delay, $view, $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->later($delay, $view, $queue); + } + + } + /** + * + * + * @see \Illuminate\Notifications\ChannelManager + * @see \Illuminate\Support\Testing\Fakes\NotificationFake + */ + class Notification { + /** + * Send the given notification to the given notifiable entities. + * + * @param \Illuminate\Support\Collection|array|mixed $notifiables + * @param mixed $notification + * @return void + * @static + */ + public static function send($notifiables, $notification) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + $instance->send($notifiables, $notification); + } + + /** + * Send the given notification immediately. + * + * @param \Illuminate\Support\Collection|array|mixed $notifiables + * @param mixed $notification + * @param array|null $channels + * @return void + * @static + */ + public static function sendNow($notifiables, $notification, $channels = null) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + $instance->sendNow($notifiables, $notification, $channels); + } + + /** + * Get a channel instance. + * + * @param string|null $name + * @return mixed + * @static + */ + public static function channel($name = null) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->channel($name); + } + + /** + * Get the default channel driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Get the default channel driver name. + * + * @return string + * @static + */ + public static function deliversVia() + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->deliversVia(); + } + + /** + * Set the default channel driver name. + * + * @param string $channel + * @return void + * @static + */ + public static function deliverVia($channel) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + $instance->deliverVia($channel); + } + + /** + * Set the locale of notifications. + * + * @param string $locale + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function locale($locale) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->locale($locale); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function driver($driver = null) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->driver($driver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function extend($driver, $callback) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get all of the created "drivers". + * + * @return array + * @static + */ + public static function getDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->getDrivers(); + } + + /** + * Get the container instance used by the manager. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the manager. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->setContainer($container); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function forgetDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->forgetDrivers(); + } + + /** + * Assert if a notification was sent on-demand based on a truth-test callback. + * + * @param string|\Closure $notification + * @param callable|null $callback + * @return void + * @throws \Exception + * @static + */ + public static function assertSentOnDemand($notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentOnDemand($notification, $callback); + } + + /** + * Assert if a notification was sent based on a truth-test callback. + * + * @param mixed $notifiable + * @param string|\Closure $notification + * @param callable|null $callback + * @return void + * @throws \Exception + * @static + */ + public static function assertSentTo($notifiable, $notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentTo($notifiable, $notification, $callback); + } + + /** + * Assert if a notification was sent on-demand a number of times. + * + * @param string $notification + * @param int $times + * @return void + * @static + */ + public static function assertSentOnDemandTimes($notification, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentOnDemandTimes($notification, $times); + } + + /** + * Assert if a notification was sent a number of times. + * + * @param mixed $notifiable + * @param string $notification + * @param int $times + * @return void + * @static + */ + public static function assertSentToTimes($notifiable, $notification, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentToTimes($notifiable, $notification, $times); + } + + /** + * Determine if a notification was sent based on a truth-test callback. + * + * @param mixed $notifiable + * @param string|\Closure $notification + * @param callable|null $callback + * @return void + * @throws \Exception + * @static + */ + public static function assertNotSentTo($notifiable, $notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertNotSentTo($notifiable, $notification, $callback); + } + + /** + * Assert that no notifications were sent. + * + * @return void + * @static + */ + public static function assertNothingSent() + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertNothingSent(); + } + + /** + * Assert that no notifications were sent to the given notifiable. + * + * @param mixed $notifiable + * @return void + * @throws \Exception + * @static + */ + public static function assertNothingSentTo($notifiable) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertNothingSentTo($notifiable); + } + + /** + * Assert the total amount of times a notification was sent. + * + * @param string $notification + * @param int $expectedCount + * @return void + * @static + */ + public static function assertSentTimes($notification, $expectedCount) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentTimes($notification, $expectedCount); + } + + /** + * Assert the total count of notification that were sent. + * + * @param int $expectedCount + * @return void + * @static + */ + public static function assertCount($expectedCount) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertCount($expectedCount); + } + + /** + * Get all of the notifications matching a truth-test callback. + * + * @param mixed $notifiable + * @param string $notification + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function sent($notifiable, $notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->sent($notifiable, $notification, $callback); + } + + /** + * Determine if there are more notifications left to inspect. + * + * @param mixed $notifiable + * @param string $notification + * @return bool + * @static + */ + public static function hasSent($notifiable, $notification) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->hasSent($notifiable, $notification); + } + + /** + * Specify if notification should be serialized and restored when being "pushed" to the queue. + * + * @param bool $serializeAndRestore + * @return \Illuminate\Support\Testing\Fakes\NotificationFake + * @static + */ + public static function serializeAndRestore($serializeAndRestore = true) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->serializeAndRestore($serializeAndRestore); + } + + /** + * Get the notifications that have been sent. + * + * @return array + * @static + */ + public static function sentNotifications() + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->sentNotifications(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Support\Testing\Fakes\NotificationFake::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Support\Testing\Fakes\NotificationFake::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Support\Testing\Fakes\NotificationFake::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Support\Testing\Fakes\NotificationFake::flushMacros(); + } + + } + /** + * + * + * @method static string sendResetLink(array $credentials, \Closure|null $callback = null) + * @method static mixed reset(array $credentials, \Closure $callback) + * @method static \Illuminate\Contracts\Auth\CanResetPassword|null getUser(array $credentials) + * @method static string createToken(\Illuminate\Contracts\Auth\CanResetPassword $user) + * @method static void deleteToken(\Illuminate\Contracts\Auth\CanResetPassword $user) + * @method static bool tokenExists(\Illuminate\Contracts\Auth\CanResetPassword $user, string $token) + * @method static \Illuminate\Auth\Passwords\TokenRepositoryInterface getRepository() + * @see \Illuminate\Auth\Passwords\PasswordBrokerManager + * @see \Illuminate\Auth\Passwords\PasswordBroker + */ + class Password { + /** + * Attempt to get the broker from the local cache. + * + * @param string|null $name + * @return \Illuminate\Contracts\Auth\PasswordBroker + * @static + */ + public static function broker($name = null) + { + /** @var \Illuminate\Auth\Passwords\PasswordBrokerManager $instance */ + return $instance->broker($name); + } + + /** + * Get the default password broker name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Auth\Passwords\PasswordBrokerManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default password broker name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Auth\Passwords\PasswordBrokerManager $instance */ + $instance->setDefaultDriver($name); + } + + } + /** + * + * + * @method static \Illuminate\Process\PendingProcess command(array|string $command) + * @method static \Illuminate\Process\PendingProcess path(string $path) + * @method static \Illuminate\Process\PendingProcess timeout(int $timeout) + * @method static \Illuminate\Process\PendingProcess idleTimeout(int $timeout) + * @method static \Illuminate\Process\PendingProcess forever() + * @method static \Illuminate\Process\PendingProcess env(array $environment) + * @method static \Illuminate\Process\PendingProcess input(\Traversable|resource|string|int|float|bool|null $input) + * @method static \Illuminate\Process\PendingProcess quietly() + * @method static \Illuminate\Process\PendingProcess tty(bool $tty = true) + * @method static \Illuminate\Process\PendingProcess options(array $options) + * @method static \Illuminate\Contracts\Process\ProcessResult run(array|string|null $command = null, callable|null $output = null) + * @method static \Illuminate\Process\InvokedProcess start(array|string|null $command = null, callable|null $output = null) + * @method static bool supportsTty() + * @method static \Illuminate\Process\PendingProcess withFakeHandlers(array $fakeHandlers) + * @method static \Illuminate\Process\PendingProcess|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @method static \Illuminate\Process\PendingProcess|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @see \Illuminate\Process\PendingProcess + * @see \Illuminate\Process\Factory + */ + class Process { + /** + * Create a new fake process response for testing purposes. + * + * @param array|string $output + * @param array|string $errorOutput + * @param int $exitCode + * @return \Illuminate\Process\FakeProcessResult + * @static + */ + public static function result($output = '', $errorOutput = '', $exitCode = 0) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->result($output, $errorOutput, $exitCode); + } + + /** + * Begin describing a fake process lifecycle. + * + * @return \Illuminate\Process\FakeProcessDescription + * @static + */ + public static function describe() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->describe(); + } + + /** + * Begin describing a fake process sequence. + * + * @param array $processes + * @return \Illuminate\Process\FakeProcessSequence + * @static + */ + public static function sequence($processes = []) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->sequence($processes); + } + + /** + * Indicate that the process factory should fake processes. + * + * @param \Closure|array|null $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function fake($callback = null) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->fake($callback); + } + + /** + * Determine if the process factory has fake process handlers and is recording processes. + * + * @return bool + * @static + */ + public static function isRecording() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->isRecording(); + } + + /** + * Record the given process if processes should be recorded. + * + * @param \Illuminate\Process\PendingProcess $process + * @param \Illuminate\Contracts\Process\ProcessResult $result + * @return \Illuminate\Process\Factory + * @static + */ + public static function recordIfRecording($process, $result) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->recordIfRecording($process, $result); + } + + /** + * Record the given process. + * + * @param \Illuminate\Process\PendingProcess $process + * @param \Illuminate\Contracts\Process\ProcessResult $result + * @return \Illuminate\Process\Factory + * @static + */ + public static function record($process, $result) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->record($process, $result); + } + + /** + * Indicate that an exception should be thrown if any process is not faked. + * + * @param bool $prevent + * @return \Illuminate\Process\Factory + * @static + */ + public static function preventStrayProcesses($prevent = true) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->preventStrayProcesses($prevent); + } + + /** + * Determine if stray processes are being prevented. + * + * @return bool + * @static + */ + public static function preventingStrayProcesses() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->preventingStrayProcesses(); + } + + /** + * Assert that a process was recorded matching a given truth test. + * + * @param \Closure|string $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertRan($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertRan($callback); + } + + /** + * Assert that a process was recorded a given number of times matching a given truth test. + * + * @param \Closure|string $callback + * @param int $times + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertRanTimes($callback, $times = 1) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertRanTimes($callback, $times); + } + + /** + * Assert that a process was not recorded matching a given truth test. + * + * @param \Closure|string $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertNotRan($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertNotRan($callback); + } + + /** + * Assert that a process was not recorded matching a given truth test. + * + * @param \Closure|string $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertDidntRun($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertDidntRun($callback); + } + + /** + * Assert that no processes were recorded. + * + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertNothingRan() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertNothingRan(); + } + + /** + * Start defining a pool of processes. + * + * @param callable $callback + * @return \Illuminate\Process\Pool + * @static + */ + public static function pool($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->pool($callback); + } + + /** + * Start defining a series of piped processes. + * + * @param callable|array $callback + * @return \Illuminate\Contracts\Process\ProcessResult + * @static + */ + public static function pipe($callback, $output = null) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->pipe($callback, $output); + } + + /** + * Run a pool of processes and wait for them to finish executing. + * + * @param callable $callback + * @param callable|null $output + * @return \Illuminate\Process\ProcessPoolResults + * @static + */ + public static function concurrently($callback, $output = null) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->concurrently($callback, $output); + } + + /** + * Create a new pending process associated with this factory. + * + * @return \Illuminate\Process\PendingProcess + * @static + */ + public static function newPendingProcess() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->newPendingProcess(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Process\Factory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Process\Factory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Process\Factory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Process\Factory::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Queue\QueueManager + * @see \Illuminate\Queue\Queue + * @see \Illuminate\Support\Testing\Fakes\QueueFake + */ + class Queue { + /** + * Register an event listener for the before job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function before($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->before($callback); + } + + /** + * Register an event listener for the after job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function after($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->after($callback); + } + + /** + * Register an event listener for the exception occurred job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function exceptionOccurred($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->exceptionOccurred($callback); + } + + /** + * Register an event listener for the daemon queue loop. + * + * @param mixed $callback + * @return void + * @static + */ + public static function looping($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->looping($callback); + } + + /** + * Register an event listener for the failed job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function failing($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->failing($callback); + } + + /** + * Register an event listener for the daemon queue stopping. + * + * @param mixed $callback + * @return void + * @static + */ + public static function stopping($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->stopping($callback); + } + + /** + * Determine if the driver is connected. + * + * @param string|null $name + * @return bool + * @static + */ + public static function connected($name = null) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->connected($name); + } + + /** + * Resolve a queue connection instance. + * + * @param string|null $name + * @return \Illuminate\Contracts\Queue\Queue + * @static + */ + public static function connection($name = null) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->connection($name); + } + + /** + * Add a queue connection resolver. + * + * @param string $driver + * @param \Closure $resolver + * @return void + * @static + */ + public static function extend($driver, $resolver) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->extend($driver, $resolver); + } + + /** + * Add a queue connection resolver. + * + * @param string $driver + * @param \Closure $resolver + * @return void + * @static + */ + public static function addConnector($driver, $resolver) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->addConnector($driver, $resolver); + } + + /** + * Get the name of the default queue connection. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the name of the default queue connection. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Get the full name for the given connection. + * + * @param string|null $connection + * @return string + * @static + */ + public static function getName($connection = null) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->getName($connection); + } + + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + * @static + */ + public static function getApplication() + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->getApplication(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Queue\QueueManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->setApplication($app); + } + + /** + * Specify the jobs that should be queued instead of faked. + * + * @param array|string $jobsToBeQueued + * @return \Illuminate\Support\Testing\Fakes\QueueFake + * @static + */ + public static function except($jobsToBeQueued) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->except($jobsToBeQueued); + } + + /** + * Assert if a job was pushed based on a truth-test callback. + * + * @param string|\Closure $job + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertPushed($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushed($job, $callback); + } + + /** + * Assert if a job was pushed based on a truth-test callback. + * + * @param string $queue + * @param string|\Closure $job + * @param callable|null $callback + * @return void + * @static + */ + public static function assertPushedOn($queue, $job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushedOn($queue, $job, $callback); + } + + /** + * Assert if a job was pushed with chained jobs based on a truth-test callback. + * + * @param string $job + * @param array $expectedChain + * @param callable|null $callback + * @return void + * @static + */ + public static function assertPushedWithChain($job, $expectedChain = [], $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushedWithChain($job, $expectedChain, $callback); + } + + /** + * Assert if a job was pushed with an empty chain based on a truth-test callback. + * + * @param string $job + * @param callable|null $callback + * @return void + * @static + */ + public static function assertPushedWithoutChain($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushedWithoutChain($job, $callback); + } + + /** + * Assert if a closure was pushed based on a truth-test callback. + * + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertClosurePushed($callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertClosurePushed($callback); + } + + /** + * Assert that a closure was not pushed based on a truth-test callback. + * + * @param callable|null $callback + * @return void + * @static + */ + public static function assertClosureNotPushed($callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertClosureNotPushed($callback); + } + + /** + * Determine if a job was pushed based on a truth-test callback. + * + * @param string|\Closure $job + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotPushed($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertNotPushed($job, $callback); + } + + /** + * Assert the total count of jobs that were pushed. + * + * @param int $expectedCount + * @return void + * @static + */ + public static function assertCount($expectedCount) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertCount($expectedCount); + } + + /** + * Assert that no jobs were pushed. + * + * @return void + * @static + */ + public static function assertNothingPushed() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertNothingPushed(); + } + + /** + * Get all of the jobs matching a truth-test callback. + * + * @param string $job + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function pushed($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushed($job, $callback); + } + + /** + * Get all of the raw pushes matching a truth-test callback. + * + * @param null|\Closure(string, ?string, array): bool $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function pushedRaw($callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushedRaw($callback); + } + + /** + * Determine if there are any stored jobs for a given class. + * + * @param string $job + * @return bool + * @static + */ + public static function hasPushed($job) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->hasPushed($job); + } + + /** + * Get the size of the queue. + * + * @param string|null $queue + * @return int + * @static + */ + public static function size($queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->size($queue); + } + + /** + * Push a new job onto the queue. + * + * @param string|object $job + * @param mixed $data + * @param string|null $queue + * @return mixed + * @static + */ + public static function push($job, $data = '', $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->push($job, $data, $queue); + } + + /** + * Determine if a job should be faked or actually dispatched. + * + * @param object $job + * @return bool + * @static + */ + public static function shouldFakeJob($job) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->shouldFakeJob($job); + } + + /** + * Push a raw payload onto the queue. + * + * @param string $payload + * @param string|null $queue + * @param array $options + * @return mixed + * @static + */ + public static function pushRaw($payload, $queue = null, $options = []) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushRaw($payload, $queue, $options); + } + + /** + * Push a new job onto the queue after (n) seconds. + * + * @param \DateTimeInterface|\DateInterval|int $delay + * @param string|object $job + * @param mixed $data + * @param string|null $queue + * @return mixed + * @static + */ + public static function later($delay, $job, $data = '', $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->later($delay, $job, $data, $queue); + } + + /** + * Push a new job onto the queue. + * + * @param string $queue + * @param string|object $job + * @param mixed $data + * @return mixed + * @static + */ + public static function pushOn($queue, $job, $data = '') + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushOn($queue, $job, $data); + } + + /** + * Push a new job onto a specific queue after (n) seconds. + * + * @param string $queue + * @param \DateTimeInterface|\DateInterval|int $delay + * @param string|object $job + * @param mixed $data + * @return mixed + * @static + */ + public static function laterOn($queue, $delay, $job, $data = '') + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->laterOn($queue, $delay, $job, $data); + } + + /** + * Pop the next job off of the queue. + * + * @param string|null $queue + * @return \Illuminate\Contracts\Queue\Job|null + * @static + */ + public static function pop($queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pop($queue); + } + + /** + * Push an array of jobs onto the queue. + * + * @param array $jobs + * @param mixed $data + * @param string|null $queue + * @return mixed + * @static + */ + public static function bulk($jobs, $data = '', $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->bulk($jobs, $data, $queue); + } + + /** + * Get the jobs that have been pushed. + * + * @return array + * @static + */ + public static function pushedJobs() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushedJobs(); + } + + /** + * Get the payloads that were pushed raw. + * + * @return list + * @static + */ + public static function rawPushes() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->rawPushes(); + } + + /** + * Specify if jobs should be serialized and restored when being "pushed" to the queue. + * + * @param bool $serializeAndRestore + * @return \Illuminate\Support\Testing\Fakes\QueueFake + * @static + */ + public static function serializeAndRestore($serializeAndRestore = true) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->serializeAndRestore($serializeAndRestore); + } + + /** + * Get the connection name for the queue. + * + * @return string + * @static + */ + public static function getConnectionName() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->getConnectionName(); + } + + /** + * Set the connection name for the queue. + * + * @param string $name + * @return \Illuminate\Support\Testing\Fakes\QueueFake + * @static + */ + public static function setConnectionName($name) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->setConnectionName($name); + } + + /** + * Release a reserved job back onto the queue after (n) seconds. + * + * @param string $queue + * @param \Illuminate\Queue\Jobs\DatabaseJobRecord $job + * @param int $delay + * @return mixed + * @static + */ + public static function release($queue, $job, $delay) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->release($queue, $job, $delay); + } + + /** + * Delete a reserved job from the queue. + * + * @param string $queue + * @param string $id + * @return void + * @throws \Throwable + * @static + */ + public static function deleteReserved($queue, $id) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + $instance->deleteReserved($queue, $id); + } + + /** + * Delete a reserved job from the reserved queue and release it. + * + * @param string $queue + * @param \Illuminate\Queue\Jobs\DatabaseJob $job + * @param int $delay + * @return void + * @static + */ + public static function deleteAndRelease($queue, $job, $delay) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + $instance->deleteAndRelease($queue, $job, $delay); + } + + /** + * Delete all of the jobs from the queue. + * + * @param string $queue + * @return int + * @static + */ + public static function clear($queue) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->clear($queue); + } + + /** + * Get the queue or return the default. + * + * @param string|null $queue + * @return string + * @static + */ + public static function getQueue($queue) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getQueue($queue); + } + + /** + * Get the underlying database instance. + * + * @return \Illuminate\Database\Connection + * @static + */ + public static function getDatabase() + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getDatabase(); + } + + /** + * Get the maximum number of attempts for an object-based queue handler. + * + * @param mixed $job + * @return mixed + * @static + */ + public static function getJobTries($job) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getJobTries($job); + } + + /** + * Get the backoff for an object-based queue handler. + * + * @param mixed $job + * @return mixed + * @static + */ + public static function getJobBackoff($job) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getJobBackoff($job); + } + + /** + * Get the expiration timestamp for an object-based queue handler. + * + * @param mixed $job + * @return mixed + * @static + */ + public static function getJobExpiration($job) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getJobExpiration($job); + } + + /** + * Register a callback to be executed when creating job payloads. + * + * @param callable|null $callback + * @return void + * @static + */ + public static function createPayloadUsing($callback) + { + //Method inherited from \Illuminate\Queue\Queue + \Illuminate\Queue\DatabaseQueue::createPayloadUsing($callback); + } + + /** + * Get the container instance being used by the connection. + * + * @return \Illuminate\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getContainer(); + } + + /** + * Set the IoC container instance. + * + * @param \Illuminate\Container\Container $container + * @return void + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + $instance->setContainer($container); + } + + } + /** + * + * + * @see \Illuminate\Cache\RateLimiter + */ + class RateLimiter { + /** + * Register a named limiter configuration. + * + * @param \BackedEnum|\UnitEnum|string $name + * @param \Closure $callback + * @return \Illuminate\Cache\RateLimiter + * @static + */ + public static function for($name, $callback) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->for($name, $callback); + } + + /** + * Get the given named rate limiter. + * + * @param \BackedEnum|\UnitEnum|string $name + * @return \Closure|null + * @static + */ + public static function limiter($name) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->limiter($name); + } + + /** + * Attempts to execute a callback if it's not limited. + * + * @param string $key + * @param int $maxAttempts + * @param \Closure $callback + * @param int $decaySeconds + * @return mixed + * @static + */ + public static function attempt($key, $maxAttempts, $callback, $decaySeconds = 60) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->attempt($key, $maxAttempts, $callback, $decaySeconds); + } + + /** + * Determine if the given key has been "accessed" too many times. + * + * @param string $key + * @param int $maxAttempts + * @return bool + * @static + */ + public static function tooManyAttempts($key, $maxAttempts) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->tooManyAttempts($key, $maxAttempts); + } + + /** + * Increment (by 1) the counter for a given key for a given decay time. + * + * @param string $key + * @param int $decaySeconds + * @return int + * @static + */ + public static function hit($key, $decaySeconds = 60) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->hit($key, $decaySeconds); + } + + /** + * Increment the counter for a given key for a given decay time by a given amount. + * + * @param string $key + * @param int $decaySeconds + * @param int $amount + * @return int + * @static + */ + public static function increment($key, $decaySeconds = 60, $amount = 1) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->increment($key, $decaySeconds, $amount); + } + + /** + * Decrement the counter for a given key for a given decay time by a given amount. + * + * @param string $key + * @param int $decaySeconds + * @param int $amount + * @return int + * @static + */ + public static function decrement($key, $decaySeconds = 60, $amount = 1) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->decrement($key, $decaySeconds, $amount); + } + + /** + * Get the number of attempts for the given key. + * + * @param string $key + * @return mixed + * @static + */ + public static function attempts($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->attempts($key); + } + + /** + * Reset the number of attempts for the given key. + * + * @param string $key + * @return mixed + * @static + */ + public static function resetAttempts($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->resetAttempts($key); + } + + /** + * Get the number of retries left for the given key. + * + * @param string $key + * @param int $maxAttempts + * @return int + * @static + */ + public static function remaining($key, $maxAttempts) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->remaining($key, $maxAttempts); + } + + /** + * Get the number of retries left for the given key. + * + * @param string $key + * @param int $maxAttempts + * @return int + * @static + */ + public static function retriesLeft($key, $maxAttempts) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->retriesLeft($key, $maxAttempts); + } + + /** + * Clear the hits and lockout timer for the given key. + * + * @param string $key + * @return void + * @static + */ + public static function clear($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + $instance->clear($key); + } + + /** + * Get the number of seconds until the "key" is accessible again. + * + * @param string $key + * @return int + * @static + */ + public static function availableIn($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->availableIn($key); + } + + /** + * Clean the rate limiter key from unicode characters. + * + * @param string $key + * @return string + * @static + */ + public static function cleanRateLimiterKey($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->cleanRateLimiterKey($key); + } + + } + /** + * + * + * @see \Illuminate\Routing\Redirector + */ + class Redirect { + /** + * Create a new redirect response to the previous location. + * + * @param int $status + * @param array $headers + * @param mixed $fallback + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function back($status = 302, $headers = [], $fallback = false) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->back($status, $headers, $fallback); + } + + /** + * Create a new redirect response to the current URI. + * + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function refresh($status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->refresh($status, $headers); + } + + /** + * Create a new redirect response, while putting the current URL in the session. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function guest($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->guest($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to the previously intended location. + * + * @param mixed $default + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function intended($default = '/', $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->intended($default, $status, $headers, $secure); + } + + /** + * Create a new redirect response to the given path. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function to($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->to($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to an external URL (no validation). + * + * @param string $path + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function away($path, $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->away($path, $status, $headers); + } + + /** + * Create a new redirect response to the given HTTPS path. + * + * @param string $path + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function secure($path, $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->secure($path, $status, $headers); + } + + /** + * Create a new redirect response to a named route. + * + * @param \BackedEnum|string $route + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function route($route, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->route($route, $parameters, $status, $headers); + } + + /** + * Create a new redirect response to a signed named route. + * + * @param \BackedEnum|string $route + * @param mixed $parameters + * @param \DateTimeInterface|\DateInterval|int|null $expiration + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function signedRoute($route, $parameters = [], $expiration = null, $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->signedRoute($route, $parameters, $expiration, $status, $headers); + } + + /** + * Create a new redirect response to a signed named route. + * + * @param \BackedEnum|string $route + * @param \DateTimeInterface|\DateInterval|int|null $expiration + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function temporarySignedRoute($route, $expiration, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->temporarySignedRoute($route, $expiration, $parameters, $status, $headers); + } + + /** + * Create a new redirect response to a controller action. + * + * @param string|array $action + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function action($action, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->action($action, $parameters, $status, $headers); + } + + /** + * Get the URL generator instance. + * + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function getUrlGenerator() + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->getUrlGenerator(); + } + + /** + * Set the active session store. + * + * @param \Illuminate\Session\Store $session + * @return void + * @static + */ + public static function setSession($session) + { + /** @var \Illuminate\Routing\Redirector $instance */ + $instance->setSession($session); + } + + /** + * Get the "intended" URL from the session. + * + * @return string|null + * @static + */ + public static function getIntendedUrl() + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->getIntendedUrl(); + } + + /** + * Set the "intended" URL in the session. + * + * @param string $url + * @return \Illuminate\Routing\Redirector + * @static + */ + public static function setIntendedUrl($url) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->setIntendedUrl($url); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\Redirector::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\Redirector::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\Redirector::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\Redirector::flushMacros(); + } + + } + /** + * + * + * @method static array validate(array $rules, ...$params) + * @method static array validateWithBag(string $errorBag, array $rules, ...$params) + * @method static bool hasValidSignature(bool $absolute = true) + * @see \Illuminate\Http\Request + */ + class Request { + /** + * Create a new Illuminate HTTP request from server variables. + * + * @return static + * @static + */ + public static function capture() + { + return \Illuminate\Http\Request::capture(); + } + + /** + * Return the Request instance. + * + * @return \Illuminate\Http\Request + * @static + */ + public static function instance() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->instance(); + } + + /** + * Get the request method. + * + * @return string + * @static + */ + public static function method() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->method(); + } + + /** + * Get a URI instance for the request. + * + * @return \Illuminate\Support\Uri + * @static + */ + public static function uri() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->uri(); + } + + /** + * Get the root URL for the application. + * + * @return string + * @static + */ + public static function root() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->root(); + } + + /** + * Get the URL (no query string) for the request. + * + * @return string + * @static + */ + public static function url() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->url(); + } + + /** + * Get the full URL for the request. + * + * @return string + * @static + */ + public static function fullUrl() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrl(); + } + + /** + * Get the full URL for the request with the added query string parameters. + * + * @param array $query + * @return string + * @static + */ + public static function fullUrlWithQuery($query) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrlWithQuery($query); + } + + /** + * Get the full URL for the request without the given query string parameters. + * + * @param array|string $keys + * @return string + * @static + */ + public static function fullUrlWithoutQuery($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrlWithoutQuery($keys); + } + + /** + * Get the current path info for the request. + * + * @return string + * @static + */ + public static function path() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->path(); + } + + /** + * Get the current decoded path info for the request. + * + * @return string + * @static + */ + public static function decodedPath() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->decodedPath(); + } + + /** + * Get a segment from the URI (1 based index). + * + * @param int $index + * @param string|null $default + * @return string|null + * @static + */ + public static function segment($index, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->segment($index, $default); + } + + /** + * Get all of the segments for the request path. + * + * @return array + * @static + */ + public static function segments() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->segments(); + } + + /** + * Determine if the current request URI matches a pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function is(...$patterns) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->is(...$patterns); + } + + /** + * Determine if the route name matches a given pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function routeIs(...$patterns) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->routeIs(...$patterns); + } + + /** + * Determine if the current request URL and query string match a pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function fullUrlIs(...$patterns) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrlIs(...$patterns); + } + + /** + * Get the host name. + * + * @return string + * @static + */ + public static function host() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->host(); + } + + /** + * Get the HTTP host being requested. + * + * @return string + * @static + */ + public static function httpHost() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->httpHost(); + } + + /** + * Get the scheme and HTTP host. + * + * @return string + * @static + */ + public static function schemeAndHttpHost() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->schemeAndHttpHost(); + } + + /** + * Determine if the request is the result of an AJAX call. + * + * @return bool + * @static + */ + public static function ajax() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->ajax(); + } + + /** + * Determine if the request is the result of a PJAX call. + * + * @return bool + * @static + */ + public static function pjax() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->pjax(); + } + + /** + * Determine if the request is the result of a prefetch call. + * + * @return bool + * @static + */ + public static function prefetch() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->prefetch(); + } + + /** + * Determine if the request is over HTTPS. + * + * @return bool + * @static + */ + public static function secure() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->secure(); + } + + /** + * Get the client IP address. + * + * @return string|null + * @static + */ + public static function ip() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->ip(); + } + + /** + * Get the client IP addresses. + * + * @return array + * @static + */ + public static function ips() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->ips(); + } + + /** + * Get the client user agent. + * + * @return string|null + * @static + */ + public static function userAgent() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->userAgent(); + } + + /** + * Merge new input into the current request's input array. + * + * @param array $input + * @return \Illuminate\Http\Request + * @static + */ + public static function merge($input) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->merge($input); + } + + /** + * Merge new input into the request's input, but only when that key is missing from the request. + * + * @param array $input + * @return \Illuminate\Http\Request + * @static + */ + public static function mergeIfMissing($input) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->mergeIfMissing($input); + } + + /** + * Replace the input values for the current request. + * + * @param array $input + * @return \Illuminate\Http\Request + * @static + */ + public static function replace($input) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->replace($input); + } + + /** + * This method belongs to Symfony HttpFoundation and is not usually needed when using Laravel. + * + * Instead, you may use the "input" method. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->get($key, $default); + } + + /** + * Get the JSON payload for the request. + * + * @param string|null $key + * @param mixed $default + * @return \Symfony\Component\HttpFoundation\InputBag|mixed + * @static + */ + public static function json($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->json($key, $default); + } + + /** + * Create a new request instance from the given Laravel request. + * + * @param \Illuminate\Http\Request $from + * @param \Illuminate\Http\Request|null $to + * @return static + * @static + */ + public static function createFrom($from, $to = null) + { + return \Illuminate\Http\Request::createFrom($from, $to); + } + + /** + * Create an Illuminate request from a Symfony instance. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @return static + * @static + */ + public static function createFromBase($request) + { + return \Illuminate\Http\Request::createFromBase($request); + } + + /** + * Clones a request and overrides some of its parameters. + * + * @return static + * @param array|null $query The GET parameters + * @param array|null $request The POST parameters + * @param array|null $attributes The request attributes (parameters parsed from the PATH_INFO, ...) + * @param array|null $cookies The COOKIE parameters + * @param array|null $files The FILES parameters + * @param array|null $server The SERVER parameters + * @static + */ + public static function duplicate($query = null, $request = null, $attributes = null, $cookies = null, $files = null, $server = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->duplicate($query, $request, $attributes, $cookies, $files, $server); + } + + /** + * Whether the request contains a Session object. + * + * This method does not give any information about the state of the session object, + * like whether the session is started or not. It is just a way to check if this Request + * is associated with a Session instance. + * + * @param bool $skipIfUninitialized When true, ignores factories injected by `setSessionFactory` + * @static + */ + public static function hasSession($skipIfUninitialized = false) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasSession($skipIfUninitialized); + } + + /** + * Gets the Session. + * + * @throws SessionNotFoundException When session is not set properly + * @static + */ + public static function getSession() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->getSession(); + } + + /** + * Get the session associated with the request. + * + * @return \Illuminate\Contracts\Session\Session + * @throws \RuntimeException + * @static + */ + public static function session() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->session(); + } + + /** + * Set the session instance on the request. + * + * @param \Illuminate\Contracts\Session\Session $session + * @return void + * @static + */ + public static function setLaravelSession($session) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->setLaravelSession($session); + } + + /** + * Set the locale for the request instance. + * + * @param string $locale + * @return void + * @static + */ + public static function setRequestLocale($locale) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->setRequestLocale($locale); + } + + /** + * Set the default locale for the request instance. + * + * @param string $locale + * @return void + * @static + */ + public static function setDefaultRequestLocale($locale) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->setDefaultRequestLocale($locale); + } + + /** + * Get the user making the request. + * + * @param string|null $guard + * @return mixed + * @static + */ + public static function user($guard = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->user($guard); + } + + /** + * Get the route handling the request. + * + * @param string|null $param + * @param mixed $default + * @return \Illuminate\Routing\Route|object|string|null + * @static + */ + public static function route($param = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->route($param, $default); + } + + /** + * Get a unique fingerprint for the request / route / IP address. + * + * @return string + * @throws \RuntimeException + * @static + */ + public static function fingerprint() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fingerprint(); + } + + /** + * Set the JSON payload for the request. + * + * @param \Symfony\Component\HttpFoundation\InputBag $json + * @return \Illuminate\Http\Request + * @static + */ + public static function setJson($json) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->setJson($json); + } + + /** + * Get the user resolver callback. + * + * @return \Closure + * @static + */ + public static function getUserResolver() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUserResolver(); + } + + /** + * Set the user resolver callback. + * + * @param \Closure $callback + * @return \Illuminate\Http\Request + * @static + */ + public static function setUserResolver($callback) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->setUserResolver($callback); + } + + /** + * Get the route resolver callback. + * + * @return \Closure + * @static + */ + public static function getRouteResolver() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRouteResolver(); + } + + /** + * Set the route resolver callback. + * + * @param \Closure $callback + * @return \Illuminate\Http\Request + * @static + */ + public static function setRouteResolver($callback) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->setRouteResolver($callback); + } + + /** + * Get all of the input and files for the request. + * + * @return array + * @static + */ + public static function toArray() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->toArray(); + } + + /** + * Determine if the given offset exists. + * + * @param string $offset + * @return bool + * @static + */ + public static function offsetExists($offset) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->offsetExists($offset); + } + + /** + * Get the value at the given offset. + * + * @param string $offset + * @return mixed + * @static + */ + public static function offsetGet($offset) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->offsetGet($offset); + } + + /** + * Set the value at the given offset. + * + * @param string $offset + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($offset, $value) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->offsetSet($offset, $value); + } + + /** + * Remove the value at the given offset. + * + * @param string $offset + * @return void + * @static + */ + public static function offsetUnset($offset) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->offsetUnset($offset); + } + + /** + * Sets the parameters for this request. + * + * This method also re-initializes all properties. + * + * @param array $query The GET parameters + * @param array $request The POST parameters + * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) + * @param array $cookies The COOKIE parameters + * @param array $files The FILES parameters + * @param array $server The SERVER parameters + * @param string|resource|null $content The raw body data + * @static + */ + public static function initialize($query = [], $request = [], $attributes = [], $cookies = [], $files = [], $server = [], $content = null) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->initialize($query, $request, $attributes, $cookies, $files, $server, $content); + } + + /** + * Creates a new request with values from PHP's super globals. + * + * @static + */ + public static function createFromGlobals() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::createFromGlobals(); + } + + /** + * Creates a Request based on a given URI and configuration. + * + * The information contained in the URI always take precedence + * over the other information (server and parameters). + * + * @param string $uri The URI + * @param string $method The HTTP method + * @param array $parameters The query (GET) or request (POST) parameters + * @param array $cookies The request cookies ($_COOKIE) + * @param array $files The request files ($_FILES) + * @param array $server The server parameters ($_SERVER) + * @param string|resource|null $content The raw body data + * @throws BadRequestException When the URI is invalid + * @static + */ + public static function create($uri, $method = 'GET', $parameters = [], $cookies = [], $files = [], $server = [], $content = null) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::create($uri, $method, $parameters, $cookies, $files, $server, $content); + } + + /** + * Sets a callable able to create a Request instance. + * + * This is mainly useful when you need to override the Request class + * to keep BC with an existing system. It should not be used for any + * other purpose. + * + * @static + */ + public static function setFactory($callable) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::setFactory($callable); + } + + /** + * Overrides the PHP global variables according to this request instance. + * + * It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE. + * $_FILES is never overridden, see rfc1867 + * + * @static + */ + public static function overrideGlobals() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->overrideGlobals(); + } + + /** + * Sets a list of trusted proxies. + * + * You should only list the reverse proxies that you manage directly. + * + * @param array $proxies A list of trusted proxies, the string 'REMOTE_ADDR' will be replaced with $_SERVER['REMOTE_ADDR'] and 'PRIVATE_SUBNETS' by IpUtils::PRIVATE_SUBNETS + * @param int-mask-of $trustedHeaderSet A bit field to set which headers to trust from your proxies + * @static + */ + public static function setTrustedProxies($proxies, $trustedHeaderSet) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::setTrustedProxies($proxies, $trustedHeaderSet); + } + + /** + * Gets the list of trusted proxies. + * + * @return string[] + * @static + */ + public static function getTrustedProxies() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getTrustedProxies(); + } + + /** + * Gets the set of trusted headers from trusted proxies. + * + * @return int A bit field of Request::HEADER_* that defines which headers are trusted from your proxies + * @static + */ + public static function getTrustedHeaderSet() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getTrustedHeaderSet(); + } + + /** + * Sets a list of trusted host patterns. + * + * You should only list the hosts you manage using regexs. + * + * @param array $hostPatterns A list of trusted host patterns + * @static + */ + public static function setTrustedHosts($hostPatterns) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::setTrustedHosts($hostPatterns); + } + + /** + * Gets the list of trusted host patterns. + * + * @return string[] + * @static + */ + public static function getTrustedHosts() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getTrustedHosts(); + } + + /** + * Normalizes a query string. + * + * It builds a normalized query string, where keys/value pairs are alphabetized, + * have consistent escaping and unneeded delimiters are removed. + * + * @static + */ + public static function normalizeQueryString($qs) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::normalizeQueryString($qs); + } + + /** + * Enables support for the _method request parameter to determine the intended HTTP method. + * + * Be warned that enabling this feature might lead to CSRF issues in your code. + * Check that you are using CSRF tokens when required. + * If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered + * and used to send a "PUT" or "DELETE" request via the _method request parameter. + * If these methods are not protected against CSRF, this presents a possible vulnerability. + * + * The HTTP method can only be overridden when the real HTTP method is POST. + * + * @static + */ + public static function enableHttpMethodParameterOverride() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::enableHttpMethodParameterOverride(); + } + + /** + * Checks whether support for the _method request parameter is enabled. + * + * @static + */ + public static function getHttpMethodParameterOverride() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getHttpMethodParameterOverride(); + } + + /** + * Whether the request contains a Session which was started in one of the + * previous requests. + * + * @static + */ + public static function hasPreviousSession() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasPreviousSession(); + } + + /** + * + * + * @static + */ + public static function setSession($session) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setSession($session); + } + + /** + * + * + * @internal + * @param callable(): SessionInterface $factory + * @static + */ + public static function setSessionFactory($factory) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setSessionFactory($factory); + } + + /** + * Returns the client IP addresses. + * + * In the returned array the most trusted IP address is first, and the + * least trusted one last. The "real" client IP address is the last one, + * but this is also the least trusted one. Trusted proxies are stripped. + * + * Use this method carefully; you should use getClientIp() instead. + * + * @see getClientIp() + * @static + */ + public static function getClientIps() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getClientIps(); + } + + /** + * Returns the client IP address. + * + * This method can read the client IP address from the "X-Forwarded-For" header + * when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For" + * header value is a comma+space separated list of IP addresses, the left-most + * being the original client, and each successive proxy that passed the request + * adding the IP address where it received the request from. + * + * If your reverse proxy uses a different header name than "X-Forwarded-For", + * ("Client-Ip" for instance), configure it via the $trustedHeaderSet + * argument of the Request::setTrustedProxies() method instead. + * + * @see getClientIps() + * @see https://wikipedia.org/wiki/X-Forwarded-For + * @static + */ + public static function getClientIp() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getClientIp(); + } + + /** + * Returns current script name. + * + * @static + */ + public static function getScriptName() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getScriptName(); + } + + /** + * Returns the path being requested relative to the executed script. + * + * The path info always starts with a /. + * + * Suppose this request is instantiated from /mysite on localhost: + * + * * http://localhost/mysite returns an empty string + * * http://localhost/mysite/about returns '/about' + * * http://localhost/mysite/enco%20ded returns '/enco%20ded' + * * http://localhost/mysite/about?var=1 returns '/about' + * + * @return string The raw path (i.e. not urldecoded) + * @static + */ + public static function getPathInfo() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPathInfo(); + } + + /** + * Returns the root path from which this request is executed. + * + * Suppose that an index.php file instantiates this request object: + * + * * http://localhost/index.php returns an empty string + * * http://localhost/index.php/page returns an empty string + * * http://localhost/web/index.php returns '/web' + * * http://localhost/we%20b/index.php returns '/we%20b' + * + * @return string The raw path (i.e. not urldecoded) + * @static + */ + public static function getBasePath() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getBasePath(); + } + + /** + * Returns the root URL from which this request is executed. + * + * The base URL never ends with a /. + * + * This is similar to getBasePath(), except that it also includes the + * script filename (e.g. index.php) if one exists. + * + * @return string The raw URL (i.e. not urldecoded) + * @static + */ + public static function getBaseUrl() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getBaseUrl(); + } + + /** + * Gets the request's scheme. + * + * @static + */ + public static function getScheme() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getScheme(); + } + + /** + * Returns the port on which the request is made. + * + * This method can read the client port from the "X-Forwarded-Port" header + * when trusted proxies were set via "setTrustedProxies()". + * + * The "X-Forwarded-Port" header must contain the client port. + * + * @return int|string|null Can be a string if fetched from the server bag + * @static + */ + public static function getPort() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPort(); + } + + /** + * Returns the user. + * + * @static + */ + public static function getUser() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUser(); + } + + /** + * Returns the password. + * + * @static + */ + public static function getPassword() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPassword(); + } + + /** + * Gets the user info. + * + * @return string|null A user name if any and, optionally, scheme-specific information about how to gain authorization to access the server + * @static + */ + public static function getUserInfo() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUserInfo(); + } + + /** + * Returns the HTTP host being requested. + * + * The port name will be appended to the host if it's non-standard. + * + * @static + */ + public static function getHttpHost() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getHttpHost(); + } + + /** + * Returns the requested URI (path and query string). + * + * @return string The raw URI (i.e. not URI decoded) + * @static + */ + public static function getRequestUri() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRequestUri(); + } + + /** + * Gets the scheme and HTTP host. + * + * If the URL was called with basic authentication, the user + * and the password are not added to the generated string. + * + * @static + */ + public static function getSchemeAndHttpHost() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getSchemeAndHttpHost(); + } + + /** + * Generates a normalized URI (URL) for the Request. + * + * @see getQueryString() + * @static + */ + public static function getUri() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUri(); + } + + /** + * Generates a normalized URI for the given path. + * + * @param string $path A path to use instead of the current one + * @static + */ + public static function getUriForPath($path) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUriForPath($path); + } + + /** + * Returns the path as relative reference from the current Request path. + * + * Only the URIs path component (no schema, host etc.) is relevant and must be given. + * Both paths must be absolute and not contain relative parts. + * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives. + * Furthermore, they can be used to reduce the link size in documents. + * + * Example target paths, given a base path of "/a/b/c/d": + * - "/a/b/c/d" -> "" + * - "/a/b/c/" -> "./" + * - "/a/b/" -> "../" + * - "/a/b/c/other" -> "other" + * - "/a/x/y" -> "../../x/y" + * + * @static + */ + public static function getRelativeUriForPath($path) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRelativeUriForPath($path); + } + + /** + * Generates the normalized query string for the Request. + * + * It builds a normalized query string, where keys/value pairs are alphabetized + * and have consistent escaping. + * + * @static + */ + public static function getQueryString() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getQueryString(); + } + + /** + * Checks whether the request is secure or not. + * + * This method can read the client protocol from the "X-Forwarded-Proto" header + * when trusted proxies were set via "setTrustedProxies()". + * + * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http". + * + * @static + */ + public static function isSecure() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isSecure(); + } + + /** + * Returns the host name. + * + * This method can read the client host name from the "X-Forwarded-Host" header + * when trusted proxies were set via "setTrustedProxies()". + * + * The "X-Forwarded-Host" header must contain the client host name. + * + * @throws SuspiciousOperationException when the host name is invalid or not trusted + * @static + */ + public static function getHost() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getHost(); + } + + /** + * Sets the request method. + * + * @static + */ + public static function setMethod($method) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setMethod($method); + } + + /** + * Gets the request "intended" method. + * + * If the X-HTTP-Method-Override header is set, and if the method is a POST, + * then it is used to determine the "real" intended HTTP method. + * + * The _method request parameter can also be used to determine the HTTP method, + * but only if enableHttpMethodParameterOverride() has been called. + * + * The method is always an uppercased string. + * + * @see getRealMethod() + * @static + */ + public static function getMethod() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getMethod(); + } + + /** + * Gets the "real" request method. + * + * @see getMethod() + * @static + */ + public static function getRealMethod() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRealMethod(); + } + + /** + * Gets the mime type associated with the format. + * + * @static + */ + public static function getMimeType($format) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getMimeType($format); + } + + /** + * Gets the mime types associated with the format. + * + * @return string[] + * @static + */ + public static function getMimeTypes($format) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getMimeTypes($format); + } + + /** + * Gets the format associated with the mime type. + * + * @static + */ + public static function getFormat($mimeType) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getFormat($mimeType); + } + + /** + * Associates a format with mime types. + * + * @param string|string[] $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type) + * @static + */ + public static function setFormat($format, $mimeTypes) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setFormat($format, $mimeTypes); + } + + /** + * Gets the request format. + * + * Here is the process to determine the format: + * + * * format defined by the user (with setRequestFormat()) + * * _format request attribute + * * $default + * + * @see getPreferredFormat + * @static + */ + public static function getRequestFormat($default = 'html') + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRequestFormat($default); + } + + /** + * Sets the request format. + * + * @static + */ + public static function setRequestFormat($format) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setRequestFormat($format); + } + + /** + * Gets the usual name of the format associated with the request's media type (provided in the Content-Type header). + * + * @see Request::$formats + * @static + */ + public static function getContentTypeFormat() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getContentTypeFormat(); + } + + /** + * Sets the default locale. + * + * @static + */ + public static function setDefaultLocale($locale) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setDefaultLocale($locale); + } + + /** + * Get the default locale. + * + * @static + */ + public static function getDefaultLocale() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getDefaultLocale(); + } + + /** + * Sets the locale. + * + * @static + */ + public static function setLocale($locale) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setLocale($locale); + } + + /** + * Get the locale. + * + * @static + */ + public static function getLocale() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getLocale(); + } + + /** + * Checks if the request method is of specified type. + * + * @param string $method Uppercase request method (GET, POST etc) + * @static + */ + public static function isMethod($method) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethod($method); + } + + /** + * Checks whether or not the method is safe. + * + * @see https://tools.ietf.org/html/rfc7231#section-4.2.1 + * @static + */ + public static function isMethodSafe() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethodSafe(); + } + + /** + * Checks whether or not the method is idempotent. + * + * @static + */ + public static function isMethodIdempotent() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethodIdempotent(); + } + + /** + * Checks whether the method is cacheable or not. + * + * @see https://tools.ietf.org/html/rfc7231#section-4.2.3 + * @static + */ + public static function isMethodCacheable() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethodCacheable(); + } + + /** + * Returns the protocol version. + * + * If the application is behind a proxy, the protocol version used in the + * requests between the client and the proxy and between the proxy and the + * server might be different. This returns the former (from the "Via" header) + * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns + * the latter (from the "SERVER_PROTOCOL" server parameter). + * + * @static + */ + public static function getProtocolVersion() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getProtocolVersion(); + } + + /** + * Returns the request body content. + * + * @param bool $asResource If true, a resource will be returned + * @return string|resource + * @psalm-return ($asResource is true ? resource : string) + * @static + */ + public static function getContent($asResource = false) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getContent($asResource); + } + + /** + * Gets the decoded form or json request body. + * + * @throws JsonException When the body cannot be decoded to an array + * @static + */ + public static function getPayload() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPayload(); + } + + /** + * Gets the Etags. + * + * @static + */ + public static function getETags() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getETags(); + } + + /** + * + * + * @static + */ + public static function isNoCache() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isNoCache(); + } + + /** + * Gets the preferred format for the response by inspecting, in the following order: + * * the request format set using setRequestFormat; + * * the values of the Accept HTTP header. + * + * Note that if you use this method, you should send the "Vary: Accept" header + * in the response to prevent any issues with intermediary HTTP caches. + * + * @static + */ + public static function getPreferredFormat($default = 'html') + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPreferredFormat($default); + } + + /** + * Returns the preferred language. + * + * @param string[] $locales An array of ordered available locales + * @static + */ + public static function getPreferredLanguage($locales = null) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPreferredLanguage($locales); + } + + /** + * Gets a list of languages acceptable by the client browser ordered in the user browser preferences. + * + * @return string[] + * @static + */ + public static function getLanguages() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getLanguages(); + } + + /** + * Gets a list of charsets acceptable by the client browser in preferable order. + * + * @return string[] + * @static + */ + public static function getCharsets() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getCharsets(); + } + + /** + * Gets a list of encodings acceptable by the client browser in preferable order. + * + * @return string[] + * @static + */ + public static function getEncodings() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getEncodings(); + } + + /** + * Gets a list of content types acceptable by the client browser in preferable order. + * + * @return string[] + * @static + */ + public static function getAcceptableContentTypes() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getAcceptableContentTypes(); + } + + /** + * Returns true if the request is an XMLHttpRequest. + * + * It works if your JavaScript library sets an X-Requested-With HTTP header. + * It is known to work with common JavaScript frameworks: + * + * @see https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript + * @static + */ + public static function isXmlHttpRequest() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isXmlHttpRequest(); + } + + /** + * Checks whether the client browser prefers safe content or not according to RFC8674. + * + * @see https://tools.ietf.org/html/rfc8674 + * @static + */ + public static function preferSafeContent() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->preferSafeContent(); + } + + /** + * Indicates whether this request originated from a trusted proxy. + * + * This can be useful to determine whether or not to trust the + * contents of a proxy-specific header. + * + * @static + */ + public static function isFromTrustedProxy() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isFromTrustedProxy(); + } + + /** + * Filter the given array of rules into an array of rules that are included in precognitive headers. + * + * @param array $rules + * @return array + * @static + */ + public static function filterPrecognitiveRules($rules) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->filterPrecognitiveRules($rules); + } + + /** + * Determine if the request is attempting to be precognitive. + * + * @return bool + * @static + */ + public static function isAttemptingPrecognition() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isAttemptingPrecognition(); + } + + /** + * Determine if the request is precognitive. + * + * @return bool + * @static + */ + public static function isPrecognitive() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isPrecognitive(); + } + + /** + * Determine if the request is sending JSON. + * + * @return bool + * @static + */ + public static function isJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isJson(); + } + + /** + * Determine if the current request probably expects a JSON response. + * + * @return bool + * @static + */ + public static function expectsJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->expectsJson(); + } + + /** + * Determine if the current request is asking for JSON. + * + * @return bool + * @static + */ + public static function wantsJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->wantsJson(); + } + + /** + * Determines whether the current requests accepts a given content type. + * + * @param string|array $contentTypes + * @return bool + * @static + */ + public static function accepts($contentTypes) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->accepts($contentTypes); + } + + /** + * Return the most suitable content type from the given array based on content negotiation. + * + * @param string|array $contentTypes + * @return string|null + * @static + */ + public static function prefers($contentTypes) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->prefers($contentTypes); + } + + /** + * Determine if the current request accepts any content type. + * + * @return bool + * @static + */ + public static function acceptsAnyContentType() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->acceptsAnyContentType(); + } + + /** + * Determines whether a request accepts JSON. + * + * @return bool + * @static + */ + public static function acceptsJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->acceptsJson(); + } + + /** + * Determines whether a request accepts HTML. + * + * @return bool + * @static + */ + public static function acceptsHtml() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->acceptsHtml(); + } + + /** + * Determine if the given content types match. + * + * @param string $actual + * @param string $type + * @return bool + * @static + */ + public static function matchesType($actual, $type) + { + return \Illuminate\Http\Request::matchesType($actual, $type); + } + + /** + * Get the data format expected in the response. + * + * @param string $default + * @return string + * @static + */ + public static function format($default = 'html') + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->format($default); + } + + /** + * Retrieve an old input item. + * + * @param string|null $key + * @param \Illuminate\Database\Eloquent\Model|string|array|null $default + * @return string|array|null + * @static + */ + public static function old($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->old($key, $default); + } + + /** + * Flash the input for the current request to the session. + * + * @return void + * @static + */ + public static function flash() + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flash(); + } + + /** + * Flash only some of the input to the session. + * + * @param array|mixed $keys + * @return void + * @static + */ + public static function flashOnly($keys) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flashOnly($keys); + } + + /** + * Flash only some of the input to the session. + * + * @param array|mixed $keys + * @return void + * @static + */ + public static function flashExcept($keys) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flashExcept($keys); + } + + /** + * Flush all of the old input from the session. + * + * @return void + * @static + */ + public static function flush() + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flush(); + } + + /** + * Retrieve a server variable from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function server($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->server($key, $default); + } + + /** + * Determine if a header is set on the request. + * + * @param string $key + * @return bool + * @static + */ + public static function hasHeader($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasHeader($key); + } + + /** + * Retrieve a header from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function header($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->header($key, $default); + } + + /** + * Get the bearer token from the request headers. + * + * @return string|null + * @static + */ + public static function bearerToken() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->bearerToken(); + } + + /** + * Get the keys for all of the input and files. + * + * @return array + * @static + */ + public static function keys() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->keys(); + } + + /** + * Get all of the input and files for the request. + * + * @param array|mixed|null $keys + * @return array + * @static + */ + public static function all($keys = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->all($keys); + } + + /** + * Retrieve an input item from the request. + * + * @param string|null $key + * @param mixed $default + * @return mixed + * @static + */ + public static function input($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->input($key, $default); + } + + /** + * Retrieve input from the request as a Fluent object instance. + * + * @param array|string|null $key + * @return \Illuminate\Support\Fluent + * @static + */ + public static function fluent($key = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fluent($key); + } + + /** + * Retrieve a query string item from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function query($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->query($key, $default); + } + + /** + * Retrieve a request payload item from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function post($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->post($key, $default); + } + + /** + * Determine if a cookie is set on the request. + * + * @param string $key + * @return bool + * @static + */ + public static function hasCookie($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasCookie($key); + } + + /** + * Retrieve a cookie from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function cookie($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->cookie($key, $default); + } + + /** + * Get an array of all of the files on the request. + * + * @return array + * @static + */ + public static function allFiles() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->allFiles(); + } + + /** + * Determine if the uploaded data contains a file. + * + * @param string $key + * @return bool + * @static + */ + public static function hasFile($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasFile($key); + } + + /** + * Retrieve a file from the request. + * + * @param string|null $key + * @param mixed $default + * @return \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|array|null + * @static + */ + public static function file($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->file($key, $default); + } + + /** + * Dump the items. + * + * @param mixed $keys + * @return \Illuminate\Http\Request + * @static + */ + public static function dump($keys = []) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->dump($keys); + } + + /** + * Dump the given arguments and terminate execution. + * + * @param mixed $args + * @return never + * @static + */ + public static function dd(...$args) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->dd(...$args); + } + + /** + * Determine if the data contains a given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function exists($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->exists($key); + } + + /** + * Determine if the data contains a given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->has($key); + } + + /** + * Determine if the instance contains any of the given keys. + * + * @param string|array $keys + * @return bool + * @static + */ + public static function hasAny($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasAny($keys); + } + + /** + * Apply the callback if the instance contains the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + * @static + */ + public static function whenHas($key, $callback, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->whenHas($key, $callback, $default); + } + + /** + * Determine if the instance contains a non-empty value for the given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function filled($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->filled($key); + } + + /** + * Determine if the instance contains an empty value for the given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function isNotFilled($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isNotFilled($key); + } + + /** + * Determine if the instance contains a non-empty value for any of the given keys. + * + * @param string|array $keys + * @return bool + * @static + */ + public static function anyFilled($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->anyFilled($keys); + } + + /** + * Apply the callback if the instance contains a non-empty value for the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + * @static + */ + public static function whenFilled($key, $callback, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->whenFilled($key, $callback, $default); + } + + /** + * Determine if the instance is missing a given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->missing($key); + } + + /** + * Apply the callback if the instance is missing the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + * @static + */ + public static function whenMissing($key, $callback, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->whenMissing($key, $callback, $default); + } + + /** + * Retrieve data from the instance as a Stringable instance. + * + * @param string $key + * @param mixed $default + * @return \Illuminate\Support\Stringable + * @static + */ + public static function str($key, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->str($key, $default); + } + + /** + * Retrieve data from the instance as a Stringable instance. + * + * @param string $key + * @param mixed $default + * @return \Illuminate\Support\Stringable + * @static + */ + public static function string($key, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->string($key, $default); + } + + /** + * Retrieve data as a boolean value. + * + * Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false. + * + * @param string|null $key + * @param bool $default + * @return bool + * @static + */ + public static function boolean($key = null, $default = false) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->boolean($key, $default); + } + + /** + * Retrieve data as an integer value. + * + * @param string $key + * @param int $default + * @return int + * @static + */ + public static function integer($key, $default = 0) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->integer($key, $default); + } + + /** + * Retrieve data as a float value. + * + * @param string $key + * @param float $default + * @return float + * @static + */ + public static function float($key, $default = 0.0) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->float($key, $default); + } + + /** + * Retrieve data from the instance as a Carbon instance. + * + * @param string $key + * @param string|null $format + * @param string|null $tz + * @return \Illuminate\Support\Carbon|null + * @throws \Carbon\Exceptions\InvalidFormatException + * @static + */ + public static function date($key, $format = null, $tz = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->date($key, $format, $tz); + } + + /** + * Retrieve data from the instance as an enum. + * + * @template TEnum of \BackedEnum + * @param string $key + * @param class-string $enumClass + * @return TEnum|null + * @static + */ + public static function enum($key, $enumClass) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->enum($key, $enumClass); + } + + /** + * Retrieve data from the instance as an array of enums. + * + * @template TEnum of \BackedEnum + * @param string $key + * @param class-string $enumClass + * @return TEnum[] + * @static + */ + public static function enums($key, $enumClass) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->enums($key, $enumClass); + } + + /** + * Retrieve data from the instance as an array. + * + * @param array|string|null $key + * @return array + * @static + */ + public static function array($key = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->array($key); + } + + /** + * Retrieve data from the instance as a collection. + * + * @param array|string|null $key + * @return \Illuminate\Support\Collection + * @static + */ + public static function collect($key = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->collect($key); + } + + /** + * Get a subset containing the provided keys with values from the instance data. + * + * @param array|mixed $keys + * @return array + * @static + */ + public static function only($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->only($keys); + } + + /** + * Get all of the data except for a specified array of items. + * + * @param array|mixed $keys + * @return array + * @static + */ + public static function except($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->except($keys); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Http\Request::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Http\Request::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Http\Request::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Http\Request::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Routing\ResponseFactory + */ + class Response { + /** + * Create a new response instance. + * + * @param mixed $content + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + * @static + */ + public static function make($content = '', $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->make($content, $status, $headers); + } + + /** + * Create a new "no content" response. + * + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + * @static + */ + public static function noContent($status = 204, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->noContent($status, $headers); + } + + /** + * Create a new response for a given view. + * + * @param string|array $view + * @param array $data + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + * @static + */ + public static function view($view, $data = [], $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->view($view, $data, $status, $headers); + } + + /** + * Create a new JSON response instance. + * + * @param mixed $data + * @param int $status + * @param array $headers + * @param int $options + * @return \Illuminate\Http\JsonResponse + * @static + */ + public static function json($data = [], $status = 200, $headers = [], $options = 0) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->json($data, $status, $headers, $options); + } + + /** + * Create a new JSONP response instance. + * + * @param string $callback + * @param mixed $data + * @param int $status + * @param array $headers + * @param int $options + * @return \Illuminate\Http\JsonResponse + * @static + */ + public static function jsonp($callback, $data = [], $status = 200, $headers = [], $options = 0) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->jsonp($callback, $data, $status, $headers, $options); + } + + /** + * Create a new event stream response. + * + * @param \Closure $callback + * @param array $headers + * @param \Illuminate\Http\StreamedEvent|string|null $endStreamWith + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function eventStream($callback, $headers = [], $endStreamWith = '') + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->eventStream($callback, $headers, $endStreamWith); + } + + /** + * Create a new streamed response instance. + * + * @param callable $callback + * @param int $status + * @param array $headers + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function stream($callback, $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->stream($callback, $status, $headers); + } + + /** + * Create a new streamed JSON response instance. + * + * @param array $data + * @param int $status + * @param array $headers + * @param int $encodingOptions + * @return \Symfony\Component\HttpFoundation\StreamedJsonResponse + * @static + */ + public static function streamJson($data, $status = 200, $headers = [], $encodingOptions = 15) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->streamJson($data, $status, $headers, $encodingOptions); + } + + /** + * Create a new streamed response instance as a file download. + * + * @param callable $callback + * @param string|null $name + * @param array $headers + * @param string|null $disposition + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @throws \Illuminate\Routing\Exceptions\StreamedResponseException + * @static + */ + public static function streamDownload($callback, $name = null, $headers = [], $disposition = 'attachment') + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->streamDownload($callback, $name, $headers, $disposition); + } + + /** + * Create a new file download response. + * + * @param \SplFileInfo|string $file + * @param string|null $name + * @param array $headers + * @param string|null $disposition + * @return \Symfony\Component\HttpFoundation\BinaryFileResponse + * @static + */ + public static function download($file, $name = null, $headers = [], $disposition = 'attachment') + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->download($file, $name, $headers, $disposition); + } + + /** + * Return the raw contents of a binary file. + * + * @param \SplFileInfo|string $file + * @param array $headers + * @return \Symfony\Component\HttpFoundation\BinaryFileResponse + * @static + */ + public static function file($file, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->file($file, $headers); + } + + /** + * Create a new redirect response to the given path. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectTo($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectTo($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to a named route. + * + * @param \BackedEnum|string $route + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectToRoute($route, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectToRoute($route, $parameters, $status, $headers); + } + + /** + * Create a new redirect response to a controller action. + * + * @param array|string $action + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectToAction($action, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectToAction($action, $parameters, $status, $headers); + } + + /** + * Create a new redirect response, while putting the current URL in the session. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectGuest($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectGuest($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to the previously intended location. + * + * @param string $default + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectToIntended($default = '/', $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectToIntended($default, $status, $headers, $secure); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\ResponseFactory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\ResponseFactory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\ResponseFactory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\ResponseFactory::flushMacros(); + } + + } + /** + * + * + * @method static \Illuminate\Routing\RouteRegistrar attribute(string $key, mixed $value) + * @method static \Illuminate\Routing\RouteRegistrar whereAlpha(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereAlphaNumeric(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereNumber(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereUlid(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereUuid(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereIn(array|string $parameters, array $values) + * @method static \Illuminate\Routing\RouteRegistrar as(string $value) + * @method static \Illuminate\Routing\RouteRegistrar can(\UnitEnum|string $ability, array|string $models = []) + * @method static \Illuminate\Routing\RouteRegistrar controller(string $controller) + * @method static \Illuminate\Routing\RouteRegistrar domain(\BackedEnum|string $value) + * @method static \Illuminate\Routing\RouteRegistrar middleware(array|string|null $middleware) + * @method static \Illuminate\Routing\RouteRegistrar missing(\Closure $missing) + * @method static \Illuminate\Routing\RouteRegistrar name(\BackedEnum|string $value) + * @method static \Illuminate\Routing\RouteRegistrar namespace(string|null $value) + * @method static \Illuminate\Routing\RouteRegistrar prefix(string $prefix) + * @method static \Illuminate\Routing\RouteRegistrar scopeBindings() + * @method static \Illuminate\Routing\RouteRegistrar where(array $where) + * @method static \Illuminate\Routing\RouteRegistrar withoutMiddleware(array|string $middleware) + * @method static \Illuminate\Routing\RouteRegistrar withoutScopedBindings() + * @see \Illuminate\Routing\Router + */ + class Route { + /** + * Register a new GET route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function get($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->get($uri, $action); + } + + /** + * Register a new POST route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function post($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->post($uri, $action); + } + + /** + * Register a new PUT route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function put($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->put($uri, $action); + } + + /** + * Register a new PATCH route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function patch($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->patch($uri, $action); + } + + /** + * Register a new DELETE route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function delete($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->delete($uri, $action); + } + + /** + * Register a new OPTIONS route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function options($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->options($uri, $action); + } + + /** + * Register a new route responding to all verbs. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function any($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->any($uri, $action); + } + + /** + * Register a new fallback route with the router. + * + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function fallback($action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->fallback($action); + } + + /** + * Create a redirect from one URI to another. + * + * @param string $uri + * @param string $destination + * @param int $status + * @return \Illuminate\Routing\Route + * @static + */ + public static function redirect($uri, $destination, $status = 302) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->redirect($uri, $destination, $status); + } + + /** + * Create a permanent redirect from one URI to another. + * + * @param string $uri + * @param string $destination + * @return \Illuminate\Routing\Route + * @static + */ + public static function permanentRedirect($uri, $destination) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->permanentRedirect($uri, $destination); + } + + /** + * Register a new route that returns a view. + * + * @param string $uri + * @param string $view + * @param array $data + * @param int|array $status + * @param array $headers + * @return \Illuminate\Routing\Route + * @static + */ + public static function view($uri, $view, $data = [], $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->view($uri, $view, $data, $status, $headers); + } + + /** + * Register a new route with the given verbs. + * + * @param array|string $methods + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function match($methods, $uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->match($methods, $uri, $action); + } + + /** + * Register an array of resource controllers. + * + * @param array $resources + * @param array $options + * @return void + * @static + */ + public static function resources($resources, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->resources($resources, $options); + } + + /** + * Route a resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingResourceRegistration + * @static + */ + public static function resource($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->resource($name, $controller, $options); + } + + /** + * Register an array of API resource controllers. + * + * @param array $resources + * @param array $options + * @return void + * @static + */ + public static function apiResources($resources, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->apiResources($resources, $options); + } + + /** + * Route an API resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingResourceRegistration + * @static + */ + public static function apiResource($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->apiResource($name, $controller, $options); + } + + /** + * Register an array of singleton resource controllers. + * + * @param array $singletons + * @param array $options + * @return void + * @static + */ + public static function singletons($singletons, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->singletons($singletons, $options); + } + + /** + * Route a singleton resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingSingletonResourceRegistration + * @static + */ + public static function singleton($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->singleton($name, $controller, $options); + } + + /** + * Register an array of API singleton resource controllers. + * + * @param array $singletons + * @param array $options + * @return void + * @static + */ + public static function apiSingletons($singletons, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->apiSingletons($singletons, $options); + } + + /** + * Route an API singleton resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingSingletonResourceRegistration + * @static + */ + public static function apiSingleton($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->apiSingleton($name, $controller, $options); + } + + /** + * Create a route group with shared attributes. + * + * @param array $attributes + * @param \Closure|array|string $routes + * @return \Illuminate\Routing\Router + * @static + */ + public static function group($attributes, $routes) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->group($attributes, $routes); + } + + /** + * Merge the given array with the last group stack. + * + * @param array $new + * @param bool $prependExistingPrefix + * @return array + * @static + */ + public static function mergeWithLastGroup($new, $prependExistingPrefix = true) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->mergeWithLastGroup($new, $prependExistingPrefix); + } + + /** + * Get the prefix from the last group on the stack. + * + * @return string + * @static + */ + public static function getLastGroupPrefix() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getLastGroupPrefix(); + } + + /** + * Add a route to the underlying route collection. + * + * @param array|string $methods + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function addRoute($methods, $uri, $action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->addRoute($methods, $uri, $action); + } + + /** + * Create a new Route object. + * + * @param array|string $methods + * @param string $uri + * @param mixed $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function newRoute($methods, $uri, $action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->newRoute($methods, $uri, $action); + } + + /** + * Return the response returned by the given route. + * + * @param string $name + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function respondWithRoute($name) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->respondWithRoute($name); + } + + /** + * Dispatch the request to the application. + * + * @param \Illuminate\Http\Request $request + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function dispatch($request) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->dispatch($request); + } + + /** + * Dispatch the request to a route and return the response. + * + * @param \Illuminate\Http\Request $request + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function dispatchToRoute($request) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->dispatchToRoute($request); + } + + /** + * Gather the middleware for the given route with resolved class names. + * + * @param \Illuminate\Routing\Route $route + * @return array + * @static + */ + public static function gatherRouteMiddleware($route) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->gatherRouteMiddleware($route); + } + + /** + * Resolve a flat array of middleware classes from the provided array. + * + * @param array $middleware + * @param array $excluded + * @return array + * @static + */ + public static function resolveMiddleware($middleware, $excluded = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->resolveMiddleware($middleware, $excluded); + } + + /** + * Create a response instance from the given value. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @param mixed $response + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function prepareResponse($request, $response) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->prepareResponse($request, $response); + } + + /** + * Static version of prepareResponse. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @param mixed $response + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function toResponse($request, $response) + { + return \Illuminate\Routing\Router::toResponse($request, $response); + } + + /** + * Substitute the route bindings onto the route. + * + * @param \Illuminate\Routing\Route $route + * @return \Illuminate\Routing\Route + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException<\Illuminate\Database\Eloquent\Model> + * @throws \Illuminate\Routing\Exceptions\BackedEnumCaseNotFoundException + * @static + */ + public static function substituteBindings($route) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->substituteBindings($route); + } + + /** + * Substitute the implicit route bindings for the given route. + * + * @param \Illuminate\Routing\Route $route + * @return void + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException<\Illuminate\Database\Eloquent\Model> + * @throws \Illuminate\Routing\Exceptions\BackedEnumCaseNotFoundException + * @static + */ + public static function substituteImplicitBindings($route) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->substituteImplicitBindings($route); + } + + /** + * Register a callback to run after implicit bindings are substituted. + * + * @param callable $callback + * @return \Illuminate\Routing\Router + * @static + */ + public static function substituteImplicitBindingsUsing($callback) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->substituteImplicitBindingsUsing($callback); + } + + /** + * Register a route matched event listener. + * + * @param string|callable $callback + * @return void + * @static + */ + public static function matched($callback) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->matched($callback); + } + + /** + * Get all of the defined middleware short-hand names. + * + * @return array + * @static + */ + public static function getMiddleware() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getMiddleware(); + } + + /** + * Register a short-hand name for a middleware. + * + * @param string $name + * @param string $class + * @return \Illuminate\Routing\Router + * @static + */ + public static function aliasMiddleware($name, $class) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->aliasMiddleware($name, $class); + } + + /** + * Check if a middlewareGroup with the given name exists. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMiddlewareGroup($name) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->hasMiddlewareGroup($name); + } + + /** + * Get all of the defined middleware groups. + * + * @return array + * @static + */ + public static function getMiddlewareGroups() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getMiddlewareGroups(); + } + + /** + * Register a group of middleware. + * + * @param string $name + * @param array $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function middlewareGroup($name, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->middlewareGroup($name, $middleware); + } + + /** + * Add a middleware to the beginning of a middleware group. + * + * If the middleware is already in the group, it will not be added again. + * + * @param string $group + * @param string $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function prependMiddlewareToGroup($group, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->prependMiddlewareToGroup($group, $middleware); + } + + /** + * Add a middleware to the end of a middleware group. + * + * If the middleware is already in the group, it will not be added again. + * + * @param string $group + * @param string $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function pushMiddlewareToGroup($group, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->pushMiddlewareToGroup($group, $middleware); + } + + /** + * Remove the given middleware from the specified group. + * + * @param string $group + * @param string $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function removeMiddlewareFromGroup($group, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->removeMiddlewareFromGroup($group, $middleware); + } + + /** + * Flush the router's middleware groups. + * + * @return \Illuminate\Routing\Router + * @static + */ + public static function flushMiddlewareGroups() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->flushMiddlewareGroups(); + } + + /** + * Add a new route parameter binder. + * + * @param string $key + * @param string|callable $binder + * @return void + * @static + */ + public static function bind($key, $binder) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->bind($key, $binder); + } + + /** + * Register a model binder for a wildcard. + * + * @param string $key + * @param string $class + * @param \Closure|null $callback + * @return void + * @static + */ + public static function model($key, $class, $callback = null) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->model($key, $class, $callback); + } + + /** + * Get the binding callback for a given binding. + * + * @param string $key + * @return \Closure|null + * @static + */ + public static function getBindingCallback($key) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getBindingCallback($key); + } + + /** + * Get the global "where" patterns. + * + * @return array + * @static + */ + public static function getPatterns() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getPatterns(); + } + + /** + * Set a global where pattern on all routes. + * + * @param string $key + * @param string $pattern + * @return void + * @static + */ + public static function pattern($key, $pattern) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->pattern($key, $pattern); + } + + /** + * Set a group of global where patterns on all routes. + * + * @param array $patterns + * @return void + * @static + */ + public static function patterns($patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->patterns($patterns); + } + + /** + * Determine if the router currently has a group stack. + * + * @return bool + * @static + */ + public static function hasGroupStack() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->hasGroupStack(); + } + + /** + * Get the current group stack for the router. + * + * @return array + * @static + */ + public static function getGroupStack() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getGroupStack(); + } + + /** + * Get a route parameter for the current route. + * + * @param string $key + * @param string|null $default + * @return mixed + * @static + */ + public static function input($key, $default = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->input($key, $default); + } + + /** + * Get the request currently being dispatched. + * + * @return \Illuminate\Http\Request + * @static + */ + public static function getCurrentRequest() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getCurrentRequest(); + } + + /** + * Get the currently dispatched route instance. + * + * @return \Illuminate\Routing\Route|null + * @static + */ + public static function getCurrentRoute() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getCurrentRoute(); + } + + /** + * Get the currently dispatched route instance. + * + * @return \Illuminate\Routing\Route|null + * @static + */ + public static function current() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->current(); + } + + /** + * Check if a route with the given name exists. + * + * @param string|array $name + * @return bool + * @static + */ + public static function has($name) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->has($name); + } + + /** + * Get the current route name. + * + * @return string|null + * @static + */ + public static function currentRouteName() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteName(); + } + + /** + * Alias for the "currentRouteNamed" method. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function is(...$patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->is(...$patterns); + } + + /** + * Determine if the current route matches a pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function currentRouteNamed(...$patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteNamed(...$patterns); + } + + /** + * Get the current route action. + * + * @return string|null + * @static + */ + public static function currentRouteAction() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteAction(); + } + + /** + * Alias for the "currentRouteUses" method. + * + * @param array|string $patterns + * @return bool + * @static + */ + public static function uses(...$patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->uses(...$patterns); + } + + /** + * Determine if the current route action matches a given action. + * + * @param string $action + * @return bool + * @static + */ + public static function currentRouteUses($action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteUses($action); + } + + /** + * Set the unmapped global resource parameters to singular. + * + * @param bool $singular + * @return void + * @static + */ + public static function singularResourceParameters($singular = true) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->singularResourceParameters($singular); + } + + /** + * Set the global resource parameter mapping. + * + * @param array $parameters + * @return void + * @static + */ + public static function resourceParameters($parameters = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->resourceParameters($parameters); + } + + /** + * Get or set the verbs used in the resource URIs. + * + * @param array $verbs + * @return array|null + * @static + */ + public static function resourceVerbs($verbs = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->resourceVerbs($verbs); + } + + /** + * Get the underlying route collection. + * + * @return \Illuminate\Routing\RouteCollectionInterface + * @static + */ + public static function getRoutes() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getRoutes(); + } + + /** + * Set the route collection instance. + * + * @param \Illuminate\Routing\RouteCollection $routes + * @return void + * @static + */ + public static function setRoutes($routes) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->setRoutes($routes); + } + + /** + * Set the compiled route collection instance. + * + * @param array $routes + * @return void + * @static + */ + public static function setCompiledRoutes($routes) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->setCompiledRoutes($routes); + } + + /** + * Remove any duplicate middleware from the given array. + * + * @param array $middleware + * @return array + * @static + */ + public static function uniqueMiddleware($middleware) + { + return \Illuminate\Routing\Router::uniqueMiddleware($middleware); + } + + /** + * Set the container instance used by the router. + * + * @param \Illuminate\Container\Container $container + * @return \Illuminate\Routing\Router + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->setContainer($container); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\Router::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\Router::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\Router::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\Router::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->macroCall($method, $parameters); + } + + /** + * Call the given Closure with this instance then return the instance. + * + * @param (callable($this): mixed)|null $callback + * @return ($callback is null ? \Illuminate\Support\HigherOrderTapProxy : $this) + * @static + */ + public static function tap($callback = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->tap($callback); + } + + } + /** + * + * + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes withoutOverlapping(int $expiresAt = 1440) + * @method static void mergeAttributes(\Illuminate\Console\Scheduling\Event $event) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes user(string $user) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes environments(array|mixed $environments) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes evenInMaintenanceMode() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes onOneServer() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes runInBackground() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes when(\Closure|bool $callback) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes skip(\Closure|bool $callback) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes name(string $description) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes description(string $description) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes cron(string $expression) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes between(string $startTime, string $endTime) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes unlessBetween(string $startTime, string $endTime) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everySecond() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwoSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFiveSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTenSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFifteenSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwentySeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThirtySeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyMinute() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwoMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThreeMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFourMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFiveMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTenMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFifteenMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThirtyMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes hourly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes hourlyAt(array|string|int|int[] $offset) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyOddHour(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwoHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThreeHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFourHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everySixHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes daily() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes at(string $time) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes dailyAt(string $time) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes twiceDaily(int $first = 1, int $second = 13) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes twiceDailyAt(int $first = 1, int $second = 13, int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weekdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weekends() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes mondays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes tuesdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes wednesdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes thursdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes fridays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes saturdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes sundays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weekly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weeklyOn(array|mixed $dayOfWeek, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes monthly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes monthlyOn(int $dayOfMonth = 1, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes twiceMonthly(int $first = 1, int $second = 16, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes lastDayOfMonth(string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes quarterly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes quarterlyOn(int $dayOfQuarter = 1, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes yearly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes yearlyOn(int $month = 1, int|string $dayOfMonth = 1, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes days(array|mixed $days) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes timezone(\DateTimeZone|string $timezone) + * @see \Illuminate\Console\Scheduling\Schedule + */ + class Schedule { + /** + * Add a new callback event to the schedule. + * + * @param string|callable $callback + * @param array $parameters + * @return \Illuminate\Console\Scheduling\CallbackEvent + * @static + */ + public static function call($callback, $parameters = []) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->call($callback, $parameters); + } + + /** + * Add a new Artisan command event to the schedule. + * + * @param string $command + * @param array $parameters + * @return \Illuminate\Console\Scheduling\Event + * @static + */ + public static function command($command, $parameters = []) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->command($command, $parameters); + } + + /** + * Add a new job callback event to the schedule. + * + * @param object|string $job + * @param string|null $queue + * @param string|null $connection + * @return \Illuminate\Console\Scheduling\CallbackEvent + * @static + */ + public static function job($job, $queue = null, $connection = null) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->job($job, $queue, $connection); + } + + /** + * Add a new command event to the schedule. + * + * @param string $command + * @param array $parameters + * @return \Illuminate\Console\Scheduling\Event + * @static + */ + public static function exec($command, $parameters = []) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->exec($command, $parameters); + } + + /** + * Create new schedule group. + * + * @param \Illuminate\Console\Scheduling\Event $event + * @return void + * @throws \RuntimeException + * @static + */ + public static function group($events) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + $instance->group($events); + } + + /** + * Compile array input for a command. + * + * @param string|int $key + * @param array $value + * @return string + * @static + */ + public static function compileArrayInput($key, $value) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->compileArrayInput($key, $value); + } + + /** + * Determine if the server is allowed to run this event. + * + * @param \Illuminate\Console\Scheduling\Event $event + * @param \DateTimeInterface $time + * @return bool + * @static + */ + public static function serverShouldRun($event, $time) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->serverShouldRun($event, $time); + } + + /** + * Get all of the events on the schedule that are due. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Support\Collection + * @static + */ + public static function dueEvents($app) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->dueEvents($app); + } + + /** + * Get all of the events on the schedule. + * + * @return \Illuminate\Console\Scheduling\Event[] + * @static + */ + public static function events() + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->events(); + } + + /** + * Specify the cache store that should be used to store mutexes. + * + * @param string $store + * @return \Illuminate\Console\Scheduling\Schedule + * @static + */ + public static function useCache($store) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->useCache($store); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Console\Scheduling\Schedule::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Console\Scheduling\Schedule::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Console\Scheduling\Schedule::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Console\Scheduling\Schedule::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Database\Schema\Builder + */ + class Schema { + /** + * Drop all tables from the database. + * + * @return void + * @static + */ + public static function dropAllTables() + { + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropAllTables(); + } + + /** + * Drop all views from the database. + * + * @return void + * @static + */ + public static function dropAllViews() + { + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropAllViews(); + } + + /** + * Get the names of current schemas for the connection. + * + * @return string[]|null + * @static + */ + public static function getCurrentSchemaListing() + { + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getCurrentSchemaListing(); + } + + /** + * Set the default string length for migrations. + * + * @param int $length + * @return void + * @static + */ + public static function defaultStringLength($length) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::defaultStringLength($length); + } + + /** + * Set the default time precision for migrations. + * + * @static + */ + public static function defaultTimePrecision($precision) + { + //Method inherited from \Illuminate\Database\Schema\Builder + return \Illuminate\Database\Schema\MySqlBuilder::defaultTimePrecision($precision); + } + + /** + * Set the default morph key type for migrations. + * + * @param string $type + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function defaultMorphKeyType($type) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::defaultMorphKeyType($type); + } + + /** + * Set the default morph key type for migrations to UUIDs. + * + * @return void + * @static + */ + public static function morphUsingUuids() + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::morphUsingUuids(); + } + + /** + * Set the default morph key type for migrations to ULIDs. + * + * @return void + * @static + */ + public static function morphUsingUlids() + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::morphUsingUlids(); + } + + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + * @static + */ + public static function createDatabase($name) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->createDatabase($name); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + * @static + */ + public static function dropDatabaseIfExists($name) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->dropDatabaseIfExists($name); + } + + /** + * Get the schemas that belong to the connection. + * + * @return array + * @static + */ + public static function getSchemas() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getSchemas(); + } + + /** + * Determine if the given table exists. + * + * @param string $table + * @return bool + * @static + */ + public static function hasTable($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasTable($table); + } + + /** + * Determine if the given view exists. + * + * @param string $view + * @return bool + * @static + */ + public static function hasView($view) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasView($view); + } + + /** + * Get the tables that belong to the connection. + * + * @param string|string[]|null $schema + * @return array + * @static + */ + public static function getTables($schema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getTables($schema); + } + + /** + * Get the names of the tables that belong to the connection. + * + * @param string|string[]|null $schema + * @param bool $schemaQualified + * @return array + * @static + */ + public static function getTableListing($schema = null, $schemaQualified = true) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getTableListing($schema, $schemaQualified); + } + + /** + * Get the views that belong to the connection. + * + * @param string|string[]|null $schema + * @return array + * @static + */ + public static function getViews($schema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getViews($schema); + } + + /** + * Get the user-defined types that belong to the connection. + * + * @param string|string[]|null $schema + * @return array + * @static + */ + public static function getTypes($schema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getTypes($schema); + } + + /** + * Determine if the given table has a given column. + * + * @param string $table + * @param string $column + * @return bool + * @static + */ + public static function hasColumn($table, $column) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasColumn($table, $column); + } + + /** + * Determine if the given table has given columns. + * + * @param string $table + * @param array $columns + * @return bool + * @static + */ + public static function hasColumns($table, $columns) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasColumns($table, $columns); + } + + /** + * Execute a table builder callback if the given table has a given column. + * + * @param string $table + * @param string $column + * @param \Closure $callback + * @return void + * @static + */ + public static function whenTableHasColumn($table, $column, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->whenTableHasColumn($table, $column, $callback); + } + + /** + * Execute a table builder callback if the given table doesn't have a given column. + * + * @param string $table + * @param string $column + * @param \Closure $callback + * @return void + * @static + */ + public static function whenTableDoesntHaveColumn($table, $column, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->whenTableDoesntHaveColumn($table, $column, $callback); + } + + /** + * Get the data type for the given column name. + * + * @param string $table + * @param string $column + * @param bool $fullDefinition + * @return string + * @static + */ + public static function getColumnType($table, $column, $fullDefinition = false) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getColumnType($table, $column, $fullDefinition); + } + + /** + * Get the column listing for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getColumnListing($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getColumnListing($table); + } + + /** + * Get the columns for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getColumns($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getColumns($table); + } + + /** + * Get the indexes for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getIndexes($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getIndexes($table); + } + + /** + * Get the names of the indexes for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getIndexListing($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getIndexListing($table); + } + + /** + * Determine if the given table has a given index. + * + * @param string $table + * @param string|array $index + * @param string|null $type + * @return bool + * @static + */ + public static function hasIndex($table, $index, $type = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasIndex($table, $index, $type); + } + + /** + * Get the foreign keys for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getForeignKeys($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getForeignKeys($table); + } + + /** + * Modify a table on the schema. + * + * @param string $table + * @param \Closure $callback + * @return void + * @static + */ + public static function table($table, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->table($table, $callback); + } + + /** + * Create a new table on the schema. + * + * @param string $table + * @param \Closure $callback + * @return void + * @static + */ + public static function create($table, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->create($table, $callback); + } + + /** + * Drop a table from the schema. + * + * @param string $table + * @return void + * @static + */ + public static function drop($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->drop($table); + } + + /** + * Drop a table from the schema if it exists. + * + * @param string $table + * @return void + * @static + */ + public static function dropIfExists($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropIfExists($table); + } + + /** + * Drop columns from a table schema. + * + * @param string $table + * @param string|array $columns + * @return void + * @static + */ + public static function dropColumns($table, $columns) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropColumns($table, $columns); + } + + /** + * Drop all types from the database. + * + * @return void + * @throws \LogicException + * @static + */ + public static function dropAllTypes() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropAllTypes(); + } + + /** + * Rename a table on the schema. + * + * @param string $from + * @param string $to + * @return void + * @static + */ + public static function rename($from, $to) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->rename($from, $to); + } + + /** + * Enable foreign key constraints. + * + * @return bool + * @static + */ + public static function enableForeignKeyConstraints() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->enableForeignKeyConstraints(); + } + + /** + * Disable foreign key constraints. + * + * @return bool + * @static + */ + public static function disableForeignKeyConstraints() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->disableForeignKeyConstraints(); + } + + /** + * Disable foreign key constraints during the execution of a callback. + * + * @param \Closure $callback + * @return mixed + * @static + */ + public static function withoutForeignKeyConstraints($callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->withoutForeignKeyConstraints($callback); + } + + /** + * Get the default schema name for the connection. + * + * @return string|null + * @static + */ + public static function getCurrentSchemaName() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getCurrentSchemaName(); + } + + /** + * Parse the given database object reference and extract the schema and table. + * + * @param string $reference + * @param string|bool|null $withDefaultSchema + * @return array + * @static + */ + public static function parseSchemaAndTable($reference, $withDefaultSchema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->parseSchemaAndTable($reference, $withDefaultSchema); + } + + /** + * Get the database connection instance. + * + * @return \Illuminate\Database\Connection + * @static + */ + public static function getConnection() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getConnection(); + } + + /** + * Set the Schema Blueprint resolver callback. + * + * @param \Closure $resolver + * @return void + * @static + */ + public static function blueprintResolver($resolver) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->blueprintResolver($resolver); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + //Method inherited from \Illuminate\Database\Schema\Builder + return \Illuminate\Database\Schema\MySqlBuilder::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Session\SessionManager + */ + class Session { + /** + * Determine if requests for the same session should wait for each to finish before executing. + * + * @return bool + * @static + */ + public static function shouldBlock() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->shouldBlock(); + } + + /** + * Get the name of the cache store / driver that should be used to acquire session locks. + * + * @return string|null + * @static + */ + public static function blockDriver() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->blockDriver(); + } + + /** + * Get the maximum number of seconds the session lock should be held for. + * + * @return int + * @static + */ + public static function defaultRouteBlockLockSeconds() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->defaultRouteBlockLockSeconds(); + } + + /** + * Get the maximum number of seconds to wait while attempting to acquire a route block session lock. + * + * @return int + * @static + */ + public static function defaultRouteBlockWaitSeconds() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->defaultRouteBlockWaitSeconds(); + } + + /** + * Get the session configuration. + * + * @return array + * @static + */ + public static function getSessionConfig() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getSessionConfig(); + } + + /** + * Get the default session driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default session driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Session\SessionManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function driver($driver = null) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->driver($driver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Session\SessionManager + * @static + */ + public static function extend($driver, $callback) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get all of the created "drivers". + * + * @return array + * @static + */ + public static function getDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getDrivers(); + } + + /** + * Get the container instance used by the manager. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the manager. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Session\SessionManager + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->setContainer($container); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Session\SessionManager + * @static + */ + public static function forgetDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->forgetDrivers(); + } + + /** + * Start the session, reading the data from a handler. + * + * @return bool + * @static + */ + public static function start() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->start(); + } + + /** + * Save the session data to storage. + * + * @return void + * @static + */ + public static function save() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->save(); + } + + /** + * Age the flash data for the session. + * + * @return void + * @static + */ + public static function ageFlashData() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->ageFlashData(); + } + + /** + * Get all of the session data. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->all(); + } + + /** + * Get a subset of the session data. + * + * @param array $keys + * @return array + * @static + */ + public static function only($keys) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->only($keys); + } + + /** + * Get all the session data except for a specified array of items. + * + * @param array $keys + * @return array + * @static + */ + public static function except($keys) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->except($keys); + } + + /** + * Checks if a key exists. + * + * @param string|array $key + * @return bool + * @static + */ + public static function exists($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->exists($key); + } + + /** + * Determine if the given key is missing from the session data. + * + * @param string|array $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->missing($key); + } + + /** + * Determine if a key is present and not null. + * + * @param string|array $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->has($key); + } + + /** + * Determine if any of the given keys are present and not null. + * + * @param string|array $key + * @return bool + * @static + */ + public static function hasAny($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->hasAny($key); + } + + /** + * Get an item from the session. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->get($key, $default); + } + + /** + * Get the value of a given key and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pull($key, $default = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->pull($key, $default); + } + + /** + * Determine if the session contains old input. + * + * @param string|null $key + * @return bool + * @static + */ + public static function hasOldInput($key = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->hasOldInput($key); + } + + /** + * Get the requested item from the flashed input array. + * + * @param string|null $key + * @param mixed $default + * @return mixed + * @static + */ + public static function getOldInput($key = null, $default = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getOldInput($key, $default); + } + + /** + * Replace the given session attributes entirely. + * + * @param array $attributes + * @return void + * @static + */ + public static function replace($attributes) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->replace($attributes); + } + + /** + * Put a key / value pair or array of key / value pairs in the session. + * + * @param string|array $key + * @param mixed $value + * @return void + * @static + */ + public static function put($key, $value = null) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->put($key, $value); + } + + /** + * Get an item from the session, or store the default value. + * + * @param string $key + * @param \Closure $callback + * @return mixed + * @static + */ + public static function remember($key, $callback) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->remember($key, $callback); + } + + /** + * Push a value onto a session array. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function push($key, $value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->push($key, $value); + } + + /** + * Increment the value of an item in the session. + * + * @param string $key + * @param int $amount + * @return mixed + * @static + */ + public static function increment($key, $amount = 1) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->increment($key, $amount); + } + + /** + * Decrement the value of an item in the session. + * + * @param string $key + * @param int $amount + * @return int + * @static + */ + public static function decrement($key, $amount = 1) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->decrement($key, $amount); + } + + /** + * Flash a key / value pair to the session. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function flash($key, $value = true) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->flash($key, $value); + } + + /** + * Flash a key / value pair to the session for immediate use. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function now($key, $value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->now($key, $value); + } + + /** + * Reflash all of the session flash data. + * + * @return void + * @static + */ + public static function reflash() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->reflash(); + } + + /** + * Reflash a subset of the current flash data. + * + * @param array|mixed $keys + * @return void + * @static + */ + public static function keep($keys = null) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->keep($keys); + } + + /** + * Flash an input array to the session. + * + * @param array $value + * @return void + * @static + */ + public static function flashInput($value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->flashInput($value); + } + + /** + * Remove an item from the session, returning its value. + * + * @param string $key + * @return mixed + * @static + */ + public static function remove($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->remove($key); + } + + /** + * Remove one or many items from the session. + * + * @param string|array $keys + * @return void + * @static + */ + public static function forget($keys) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->forget($keys); + } + + /** + * Remove all of the items from the session. + * + * @return void + * @static + */ + public static function flush() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->flush(); + } + + /** + * Flush the session data and regenerate the ID. + * + * @return bool + * @static + */ + public static function invalidate() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->invalidate(); + } + + /** + * Generate a new session identifier. + * + * @param bool $destroy + * @return bool + * @static + */ + public static function regenerate($destroy = false) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->regenerate($destroy); + } + + /** + * Generate a new session ID for the session. + * + * @param bool $destroy + * @return bool + * @static + */ + public static function migrate($destroy = false) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->migrate($destroy); + } + + /** + * Determine if the session has been started. + * + * @return bool + * @static + */ + public static function isStarted() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->isStarted(); + } + + /** + * Get the name of the session. + * + * @return string + * @static + */ + public static function getName() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getName(); + } + + /** + * Set the name of the session. + * + * @param string $name + * @return void + * @static + */ + public static function setName($name) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setName($name); + } + + /** + * Get the current session ID. + * + * @return string + * @static + */ + public static function id() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->id(); + } + + /** + * Get the current session ID. + * + * @return string + * @static + */ + public static function getId() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getId(); + } + + /** + * Set the session ID. + * + * @param string|null $id + * @return void + * @static + */ + public static function setId($id) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setId($id); + } + + /** + * Determine if this is a valid session ID. + * + * @param string|null $id + * @return bool + * @static + */ + public static function isValidId($id) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->isValidId($id); + } + + /** + * Set the existence of the session on the handler if applicable. + * + * @param bool $value + * @return void + * @static + */ + public static function setExists($value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setExists($value); + } + + /** + * Get the CSRF token value. + * + * @return string + * @static + */ + public static function token() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->token(); + } + + /** + * Regenerate the CSRF token value. + * + * @return void + * @static + */ + public static function regenerateToken() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->regenerateToken(); + } + + /** + * Determine if the previous URI is available. + * + * @return bool + * @static + */ + public static function hasPreviousUri() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->hasPreviousUri(); + } + + /** + * Get the previous URL from the session as a URI instance. + * + * @return \Illuminate\Support\Uri + * @throws \RuntimeException + * @static + */ + public static function previousUri() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->previousUri(); + } + + /** + * Get the previous URL from the session. + * + * @return string|null + * @static + */ + public static function previousUrl() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->previousUrl(); + } + + /** + * Set the "previous" URL in the session. + * + * @param string $url + * @return void + * @static + */ + public static function setPreviousUrl($url) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setPreviousUrl($url); + } + + /** + * Specify that the user has confirmed their password. + * + * @return void + * @static + */ + public static function passwordConfirmed() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->passwordConfirmed(); + } + + /** + * Get the underlying session handler implementation. + * + * @return \SessionHandlerInterface + * @static + */ + public static function getHandler() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getHandler(); + } + + /** + * Set the underlying session handler implementation. + * + * @param \SessionHandlerInterface $handler + * @return \SessionHandlerInterface + * @static + */ + public static function setHandler($handler) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->setHandler($handler); + } + + /** + * Determine if the session handler needs a request. + * + * @return bool + * @static + */ + public static function handlerNeedsRequest() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->handlerNeedsRequest(); + } + + /** + * Set the request on the handler instance. + * + * @param \Illuminate\Http\Request $request + * @return void + * @static + */ + public static function setRequestOnHandler($request) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setRequestOnHandler($request); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Session\Store::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Session\Store::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Session\Store::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Session\Store::flushMacros(); + } + + } + /** + * + * + * @method static bool has(string $location) + * @method static string read(string $location) + * @method static \League\Flysystem\DirectoryListing listContents(string $location, bool $deep = false) + * @method static int fileSize(string $path) + * @method static string visibility(string $path) + * @method static void write(string $location, string $contents, array $config = []) + * @method static void createDirectory(string $location, array $config = []) + * @see \Illuminate\Filesystem\FilesystemManager + */ + class Storage { + /** + * Get a filesystem instance. + * + * @param string|null $name + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function drive($name = null) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->drive($name); + } + + /** + * Get a filesystem instance. + * + * @param string|null $name + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function disk($name = null) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->disk($name); + } + + /** + * Get a default cloud filesystem instance. + * + * @return \Illuminate\Contracts\Filesystem\Cloud + * @static + */ + public static function cloud() + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->cloud(); + } + + /** + * Build an on-demand disk. + * + * @param string|array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->build($config); + } + + /** + * Create an instance of the local driver. + * + * @param array $config + * @param string $name + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createLocalDriver($config, $name = 'local') + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createLocalDriver($config, $name); + } + + /** + * Create an instance of the ftp driver. + * + * @param array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createFtpDriver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createFtpDriver($config); + } + + /** + * Create an instance of the sftp driver. + * + * @param array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createSftpDriver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createSftpDriver($config); + } + + /** + * Create an instance of the Amazon S3 driver. + * + * @param array $config + * @return \Illuminate\Contracts\Filesystem\Cloud + * @static + */ + public static function createS3Driver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createS3Driver($config); + } + + /** + * Create a scoped driver. + * + * @param array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createScopedDriver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createScopedDriver($config); + } + + /** + * Set the given disk instance. + * + * @param string $name + * @param mixed $disk + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function set($name, $disk) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->set($name, $disk); + } + + /** + * Get the default driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Get the default cloud driver name. + * + * @return string + * @static + */ + public static function getDefaultCloudDriver() + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->getDefaultCloudDriver(); + } + + /** + * Unset the given disk instances. + * + * @param array|string $disk + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function forgetDisk($disk) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->forgetDisk($disk); + } + + /** + * Disconnect the given disk and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->setApplication($app); + } + + /** + * Determine if temporary URLs can be generated. + * + * @return bool + * @static + */ + public static function providesTemporaryUrls() + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->providesTemporaryUrls(); + } + + /** + * Get a temporary URL for the file at the given path. + * + * @param string $path + * @param \DateTimeInterface $expiration + * @param array $options + * @return string + * @static + */ + public static function temporaryUrl($path, $expiration, $options = []) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->temporaryUrl($path, $expiration, $options); + } + + /** + * Specify the name of the disk the adapter is managing. + * + * @param string $disk + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function diskName($disk) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->diskName($disk); + } + + /** + * Indicate that signed URLs should serve the corresponding files. + * + * @param bool $serve + * @param \Closure|null $urlGeneratorResolver + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function shouldServeSignedUrls($serve = true, $urlGeneratorResolver = null) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->shouldServeSignedUrls($serve, $urlGeneratorResolver); + } + + /** + * Assert that the given file or directory exists. + * + * @param string|array $path + * @param string|null $content + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertExists($path, $content = null) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertExists($path, $content); + } + + /** + * Assert that the number of files in path equals the expected count. + * + * @param string $path + * @param int $count + * @param bool $recursive + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertCount($path, $count, $recursive = false) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertCount($path, $count, $recursive); + } + + /** + * Assert that the given file or directory does not exist. + * + * @param string|array $path + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertMissing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertMissing($path); + } + + /** + * Assert that the given directory is empty. + * + * @param string $path + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertDirectoryEmpty($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertDirectoryEmpty($path); + } + + /** + * Determine if a file or directory exists. + * + * @param string $path + * @return bool + * @static + */ + public static function exists($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->exists($path); + } + + /** + * Determine if a file or directory is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function missing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->missing($path); + } + + /** + * Determine if a file exists. + * + * @param string $path + * @return bool + * @static + */ + public static function fileExists($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->fileExists($path); + } + + /** + * Determine if a file is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function fileMissing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->fileMissing($path); + } + + /** + * Determine if a directory exists. + * + * @param string $path + * @return bool + * @static + */ + public static function directoryExists($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->directoryExists($path); + } + + /** + * Determine if a directory is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function directoryMissing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->directoryMissing($path); + } + + /** + * Get the full path to the file that exists at the given relative path. + * + * @param string $path + * @return string + * @static + */ + public static function path($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->path($path); + } + + /** + * Get the contents of a file. + * + * @param string $path + * @return string|null + * @static + */ + public static function get($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->get($path); + } + + /** + * Get the contents of a file as decoded JSON. + * + * @param string $path + * @param int $flags + * @return array|null + * @static + */ + public static function json($path, $flags = 0) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->json($path, $flags); + } + + /** + * Create a streamed response for a given file. + * + * @param string $path + * @param string|null $name + * @param array $headers + * @param string|null $disposition + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function response($path, $name = null, $headers = [], $disposition = 'inline') + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->response($path, $name, $headers, $disposition); + } + + /** + * Create a streamed download response for a given file. + * + * @param \Illuminate\Http\Request $request + * @param string $path + * @param string|null $name + * @param array $headers + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function serve($request, $path, $name = null, $headers = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->serve($request, $path, $name, $headers); + } + + /** + * Create a streamed download response for a given file. + * + * @param string $path + * @param string|null $name + * @param array $headers + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function download($path, $name = null, $headers = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->download($path, $name, $headers); + } + + /** + * Write the contents of a file. + * + * @param string $path + * @param \Psr\Http\Message\StreamInterface|\Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|resource $contents + * @param mixed $options + * @return string|bool + * @static + */ + public static function put($path, $contents, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->put($path, $contents, $options); + } + + /** + * Store the uploaded file on the disk. + * + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $path + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|array|null $file + * @param mixed $options + * @return string|false + * @static + */ + public static function putFile($path, $file = null, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->putFile($path, $file, $options); + } + + /** + * Store the uploaded file on the disk with a given name. + * + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $path + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|array|null $file + * @param string|array|null $name + * @param mixed $options + * @return string|false + * @static + */ + public static function putFileAs($path, $file, $name = null, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->putFileAs($path, $file, $name, $options); + } + + /** + * Get the visibility for the given path. + * + * @param string $path + * @return string + * @static + */ + public static function getVisibility($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getVisibility($path); + } + + /** + * Set the visibility for the given path. + * + * @param string $path + * @param string $visibility + * @return bool + * @static + */ + public static function setVisibility($path, $visibility) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->setVisibility($path, $visibility); + } + + /** + * Prepend to a file. + * + * @param string $path + * @param string $data + * @param string $separator + * @return bool + * @static + */ + public static function prepend($path, $data, $separator = ' +') + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->prepend($path, $data, $separator); + } + + /** + * Append to a file. + * + * @param string $path + * @param string $data + * @param string $separator + * @return bool + * @static + */ + public static function append($path, $data, $separator = ' +') + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->append($path, $data, $separator); + } + + /** + * Delete the file at a given path. + * + * @param string|array $paths + * @return bool + * @static + */ + public static function delete($paths) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->delete($paths); + } + + /** + * Copy a file to a new location. + * + * @param string $from + * @param string $to + * @return bool + * @static + */ + public static function copy($from, $to) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->copy($from, $to); + } + + /** + * Move a file to a new location. + * + * @param string $from + * @param string $to + * @return bool + * @static + */ + public static function move($from, $to) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->move($from, $to); + } + + /** + * Get the file size of a given file. + * + * @param string $path + * @return int + * @static + */ + public static function size($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->size($path); + } + + /** + * Get the checksum for a file. + * + * @return string|false + * @throws UnableToProvideChecksum + * @static + */ + public static function checksum($path, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->checksum($path, $options); + } + + /** + * Get the mime-type of a given file. + * + * @param string $path + * @return string|false + * @static + */ + public static function mimeType($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->mimeType($path); + } + + /** + * Get the file's last modification time. + * + * @param string $path + * @return int + * @static + */ + public static function lastModified($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->lastModified($path); + } + + /** + * Get a resource to read the file. + * + * @param string $path + * @return resource|null The path resource or null on failure. + * @static + */ + public static function readStream($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->readStream($path); + } + + /** + * Write a new file using a stream. + * + * @param string $path + * @param resource $resource + * @param array $options + * @return bool + * @static + */ + public static function writeStream($path, $resource, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->writeStream($path, $resource, $options); + } + + /** + * Get the URL for the file at the given path. + * + * @param string $path + * @return string + * @throws \RuntimeException + * @static + */ + public static function url($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->url($path); + } + + /** + * Get a temporary upload URL for the file at the given path. + * + * @param string $path + * @param \DateTimeInterface $expiration + * @param array $options + * @return array + * @throws \RuntimeException + * @static + */ + public static function temporaryUploadUrl($path, $expiration, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->temporaryUploadUrl($path, $expiration, $options); + } + + /** + * Get an array of all files in a directory. + * + * @param string|null $directory + * @param bool $recursive + * @return array + * @static + */ + public static function files($directory = null, $recursive = false) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->files($directory, $recursive); + } + + /** + * Get all of the files from the given directory (recursive). + * + * @param string|null $directory + * @return array + * @static + */ + public static function allFiles($directory = null) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->allFiles($directory); + } + + /** + * Get all of the directories within a given directory. + * + * @param string|null $directory + * @param bool $recursive + * @return array + * @static + */ + public static function directories($directory = null, $recursive = false) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->directories($directory, $recursive); + } + + /** + * Get all the directories within a given directory (recursive). + * + * @param string|null $directory + * @return array + * @static + */ + public static function allDirectories($directory = null) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->allDirectories($directory); + } + + /** + * Create a directory. + * + * @param string $path + * @return bool + * @static + */ + public static function makeDirectory($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->makeDirectory($path); + } + + /** + * Recursively delete a directory. + * + * @param string $directory + * @return bool + * @static + */ + public static function deleteDirectory($directory) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->deleteDirectory($directory); + } + + /** + * Get the Flysystem driver. + * + * @return \League\Flysystem\FilesystemOperator + * @static + */ + public static function getDriver() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getDriver(); + } + + /** + * Get the Flysystem adapter. + * + * @return \League\Flysystem\FilesystemAdapter + * @static + */ + public static function getAdapter() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getAdapter(); + } + + /** + * Get the configuration values. + * + * @return array + * @static + */ + public static function getConfig() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getConfig(); + } + + /** + * Define a custom callback that generates file download responses. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function serveUsing($callback) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + $instance->serveUsing($callback); + } + + /** + * Define a custom temporary URL builder callback. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function buildTemporaryUrlsUsing($callback) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + $instance->buildTemporaryUrlsUsing($callback); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + \Illuminate\Filesystem\LocalFilesystemAdapter::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + \Illuminate\Filesystem\LocalFilesystemAdapter::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + return \Illuminate\Filesystem\LocalFilesystemAdapter::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + \Illuminate\Filesystem\LocalFilesystemAdapter::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Routing\UrlGenerator + */ + class URL { + /** + * Get the full URL for the current request. + * + * @return string + * @static + */ + public static function full() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->full(); + } + + /** + * Get the current URL for the request. + * + * @return string + * @static + */ + public static function current() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->current(); + } + + /** + * Get the URL for the previous request. + * + * @param mixed $fallback + * @return string + * @static + */ + public static function previous($fallback = false) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->previous($fallback); + } + + /** + * Get the previous path info for the request. + * + * @param mixed $fallback + * @return string + * @static + */ + public static function previousPath($fallback = false) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->previousPath($fallback); + } + + /** + * Generate an absolute URL to the given path. + * + * @param string $path + * @param mixed $extra + * @param bool|null $secure + * @return string + * @static + */ + public static function to($path, $extra = [], $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->to($path, $extra, $secure); + } + + /** + * Generate an absolute URL with the given query parameters. + * + * @param string $path + * @param array $query + * @param mixed $extra + * @param bool|null $secure + * @return string + * @static + */ + public static function query($path, $query = [], $extra = [], $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->query($path, $query, $extra, $secure); + } + + /** + * Generate a secure, absolute URL to the given path. + * + * @param string $path + * @param array $parameters + * @return string + * @static + */ + public static function secure($path, $parameters = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->secure($path, $parameters); + } + + /** + * Generate the URL to an application asset. + * + * @param string $path + * @param bool|null $secure + * @return string + * @static + */ + public static function asset($path, $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->asset($path, $secure); + } + + /** + * Generate the URL to a secure asset. + * + * @param string $path + * @return string + * @static + */ + public static function secureAsset($path) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->secureAsset($path); + } + + /** + * Generate the URL to an asset from a custom root domain such as CDN, etc. + * + * @param string $root + * @param string $path + * @param bool|null $secure + * @return string + * @static + */ + public static function assetFrom($root, $path, $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->assetFrom($root, $path, $secure); + } + + /** + * Get the default scheme for a raw URL. + * + * @param bool|null $secure + * @return string + * @static + */ + public static function formatScheme($secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatScheme($secure); + } + + /** + * Create a signed route URL for a named route. + * + * @param \BackedEnum|string $name + * @param mixed $parameters + * @param \DateTimeInterface|\DateInterval|int|null $expiration + * @param bool $absolute + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function signedRoute($name, $parameters = [], $expiration = null, $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->signedRoute($name, $parameters, $expiration, $absolute); + } + + /** + * Create a temporary signed route URL for a named route. + * + * @param \BackedEnum|string $name + * @param \DateTimeInterface|\DateInterval|int $expiration + * @param array $parameters + * @param bool $absolute + * @return string + * @static + */ + public static function temporarySignedRoute($name, $expiration, $parameters = [], $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->temporarySignedRoute($name, $expiration, $parameters, $absolute); + } + + /** + * Determine if the given request has a valid signature. + * + * @param \Illuminate\Http\Request $request + * @param bool $absolute + * @param \Closure|array $ignoreQuery + * @return bool + * @static + */ + public static function hasValidSignature($request, $absolute = true, $ignoreQuery = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->hasValidSignature($request, $absolute, $ignoreQuery); + } + + /** + * Determine if the given request has a valid signature for a relative URL. + * + * @param \Illuminate\Http\Request $request + * @param \Closure|array $ignoreQuery + * @return bool + * @static + */ + public static function hasValidRelativeSignature($request, $ignoreQuery = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->hasValidRelativeSignature($request, $ignoreQuery); + } + + /** + * Determine if the signature from the given request matches the URL. + * + * @param \Illuminate\Http\Request $request + * @param bool $absolute + * @param \Closure|array $ignoreQuery + * @return bool + * @static + */ + public static function hasCorrectSignature($request, $absolute = true, $ignoreQuery = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->hasCorrectSignature($request, $absolute, $ignoreQuery); + } + + /** + * Determine if the expires timestamp from the given request is not from the past. + * + * @param \Illuminate\Http\Request $request + * @return bool + * @static + */ + public static function signatureHasNotExpired($request) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->signatureHasNotExpired($request); + } + + /** + * Get the URL to a named route. + * + * @param \BackedEnum|string $name + * @param mixed $parameters + * @param bool $absolute + * @return string + * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException|\InvalidArgumentException + * @static + */ + public static function route($name, $parameters = [], $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->route($name, $parameters, $absolute); + } + + /** + * Get the URL for a given route instance. + * + * @param \Illuminate\Routing\Route $route + * @param mixed $parameters + * @param bool $absolute + * @return string + * @throws \Illuminate\Routing\Exceptions\UrlGenerationException + * @static + */ + public static function toRoute($route, $parameters, $absolute) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->toRoute($route, $parameters, $absolute); + } + + /** + * Get the URL to a controller action. + * + * @param string|array $action + * @param mixed $parameters + * @param bool $absolute + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function action($action, $parameters = [], $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->action($action, $parameters, $absolute); + } + + /** + * Format the array of URL parameters. + * + * @param mixed $parameters + * @return array + * @static + */ + public static function formatParameters($parameters) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatParameters($parameters); + } + + /** + * Get the base URL for the request. + * + * @param string $scheme + * @param string|null $root + * @return string + * @static + */ + public static function formatRoot($scheme, $root = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatRoot($scheme, $root); + } + + /** + * Format the given URL segments into a single URL. + * + * @param string $root + * @param string $path + * @param \Illuminate\Routing\Route|null $route + * @return string + * @static + */ + public static function format($root, $path, $route = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->format($root, $path, $route); + } + + /** + * Determine if the given path is a valid URL. + * + * @param string $path + * @return bool + * @static + */ + public static function isValidUrl($path) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->isValidUrl($path); + } + + /** + * Set the default named parameters used by the URL generator. + * + * @param array $defaults + * @return void + * @static + */ + public static function defaults($defaults) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->defaults($defaults); + } + + /** + * Get the default named parameters used by the URL generator. + * + * @return array + * @static + */ + public static function getDefaultParameters() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->getDefaultParameters(); + } + + /** + * Force the scheme for URLs. + * + * @param string|null $scheme + * @return void + * @static + */ + public static function forceScheme($scheme) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->forceScheme($scheme); + } + + /** + * Force the use of the HTTPS scheme for all generated URLs. + * + * @param bool $force + * @return void + * @static + */ + public static function forceHttps($force = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->forceHttps($force); + } + + /** + * Set the URL origin for all generated URLs. + * + * @param string|null $root + * @return void + * @static + */ + public static function useOrigin($root) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->useOrigin($root); + } + + /** + * Set the forced root URL. + * + * @param string|null $root + * @return void + * @deprecated Use useOrigin + * @static + */ + public static function forceRootUrl($root) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->forceRootUrl($root); + } + + /** + * Set the URL origin for all generated asset URLs. + * + * @param string|null $root + * @return void + * @static + */ + public static function useAssetOrigin($root) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->useAssetOrigin($root); + } + + /** + * Set a callback to be used to format the host of generated URLs. + * + * @param \Closure $callback + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function formatHostUsing($callback) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatHostUsing($callback); + } + + /** + * Set a callback to be used to format the path of generated URLs. + * + * @param \Closure $callback + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function formatPathUsing($callback) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatPathUsing($callback); + } + + /** + * Get the path formatter being used by the URL generator. + * + * @return \Closure + * @static + */ + public static function pathFormatter() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->pathFormatter(); + } + + /** + * Get the request instance. + * + * @return \Illuminate\Http\Request + * @static + */ + public static function getRequest() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->getRequest(); + } + + /** + * Set the current request instance. + * + * @param \Illuminate\Http\Request $request + * @return void + * @static + */ + public static function setRequest($request) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->setRequest($request); + } + + /** + * Set the route collection. + * + * @param \Illuminate\Routing\RouteCollectionInterface $routes + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setRoutes($routes) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setRoutes($routes); + } + + /** + * Set the session resolver for the generator. + * + * @param callable $sessionResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setSessionResolver($sessionResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setSessionResolver($sessionResolver); + } + + /** + * Set the encryption key resolver. + * + * @param callable $keyResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setKeyResolver($keyResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setKeyResolver($keyResolver); + } + + /** + * Clone a new instance of the URL generator with a different encryption key resolver. + * + * @param callable $keyResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function withKeyResolver($keyResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->withKeyResolver($keyResolver); + } + + /** + * Set the callback that should be used to attempt to resolve missing named routes. + * + * @param callable $missingNamedRouteResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function resolveMissingNamedRoutesUsing($missingNamedRouteResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->resolveMissingNamedRoutesUsing($missingNamedRouteResolver); + } + + /** + * Get the root controller namespace. + * + * @return string + * @static + */ + public static function getRootControllerNamespace() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->getRootControllerNamespace(); + } + + /** + * Set the root controller namespace. + * + * @param string $rootNamespace + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setRootControllerNamespace($rootNamespace) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setRootControllerNamespace($rootNamespace); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\UrlGenerator::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\UrlGenerator::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\UrlGenerator::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\UrlGenerator::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Validation\Factory + */ + class Validator { + /** + * Create a new Validator instance. + * + * @param array $data + * @param array $rules + * @param array $messages + * @param array $attributes + * @return \Illuminate\Validation\Validator + * @static + */ + public static function make($data, $rules, $messages = [], $attributes = []) + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->make($data, $rules, $messages, $attributes); + } + + /** + * Validate the given data against the provided rules. + * + * @param array $data + * @param array $rules + * @param array $messages + * @param array $attributes + * @return array + * @throws \Illuminate\Validation\ValidationException + * @static + */ + public static function validate($data, $rules, $messages = [], $attributes = []) + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->validate($data, $rules, $messages, $attributes); + } + + /** + * Register a custom validator extension. + * + * @param string $rule + * @param \Closure|string $extension + * @param string|null $message + * @return void + * @static + */ + public static function extend($rule, $extension, $message = null) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->extend($rule, $extension, $message); + } + + /** + * Register a custom implicit validator extension. + * + * @param string $rule + * @param \Closure|string $extension + * @param string|null $message + * @return void + * @static + */ + public static function extendImplicit($rule, $extension, $message = null) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->extendImplicit($rule, $extension, $message); + } + + /** + * Register a custom dependent validator extension. + * + * @param string $rule + * @param \Closure|string $extension + * @param string|null $message + * @return void + * @static + */ + public static function extendDependent($rule, $extension, $message = null) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->extendDependent($rule, $extension, $message); + } + + /** + * Register a custom validator message replacer. + * + * @param string $rule + * @param \Closure|string $replacer + * @return void + * @static + */ + public static function replacer($rule, $replacer) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->replacer($rule, $replacer); + } + + /** + * Indicate that unvalidated array keys should be included in validated data when the parent array is validated. + * + * @return void + * @static + */ + public static function includeUnvalidatedArrayKeys() + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->includeUnvalidatedArrayKeys(); + } + + /** + * Indicate that unvalidated array keys should be excluded from the validated data, even if the parent array was validated. + * + * @return void + * @static + */ + public static function excludeUnvalidatedArrayKeys() + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->excludeUnvalidatedArrayKeys(); + } + + /** + * Set the Validator instance resolver. + * + * @param \Closure $resolver + * @return void + * @static + */ + public static function resolver($resolver) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->resolver($resolver); + } + + /** + * Get the Translator implementation. + * + * @return \Illuminate\Contracts\Translation\Translator + * @static + */ + public static function getTranslator() + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->getTranslator(); + } + + /** + * Get the Presence Verifier implementation. + * + * @return \Illuminate\Validation\PresenceVerifierInterface + * @static + */ + public static function getPresenceVerifier() + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->getPresenceVerifier(); + } + + /** + * Set the Presence Verifier implementation. + * + * @param \Illuminate\Validation\PresenceVerifierInterface $presenceVerifier + * @return void + * @static + */ + public static function setPresenceVerifier($presenceVerifier) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->setPresenceVerifier($presenceVerifier); + } + + /** + * Get the container instance used by the validation factory. + * + * @return \Illuminate\Contracts\Container\Container|null + * @static + */ + public static function getContainer() + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the validation factory. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Validation\Factory + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->setContainer($container); + } + + } + /** + * + * + * @see \Illuminate\View\Factory + */ + class View { + /** + * Get the evaluated view contents for the given view. + * + * @param string $path + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return \Illuminate\Contracts\View\View + * @static + */ + public static function file($path, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->file($path, $data, $mergeData); + } + + /** + * Get the evaluated view contents for the given view. + * + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return \Illuminate\Contracts\View\View + * @static + */ + public static function make($view, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->make($view, $data, $mergeData); + } + + /** + * Get the first view that actually exists from the given list. + * + * @param array $views + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return \Illuminate\Contracts\View\View + * @throws \InvalidArgumentException + * @static + */ + public static function first($views, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->first($views, $data, $mergeData); + } + + /** + * Get the rendered content of the view based on a given condition. + * + * @param bool $condition + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return string + * @static + */ + public static function renderWhen($condition, $view, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderWhen($condition, $view, $data, $mergeData); + } + + /** + * Get the rendered content of the view based on the negation of a given condition. + * + * @param bool $condition + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return string + * @static + */ + public static function renderUnless($condition, $view, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderUnless($condition, $view, $data, $mergeData); + } + + /** + * Get the rendered contents of a partial from a loop. + * + * @param string $view + * @param array $data + * @param string $iterator + * @param string $empty + * @return string + * @static + */ + public static function renderEach($view, $data, $iterator, $empty = 'raw|') + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderEach($view, $data, $iterator, $empty); + } + + /** + * Determine if a given view exists. + * + * @param string $view + * @return bool + * @static + */ + public static function exists($view) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->exists($view); + } + + /** + * Get the appropriate view engine for the given path. + * + * @param string $path + * @return \Illuminate\Contracts\View\Engine + * @throws \InvalidArgumentException + * @static + */ + public static function getEngineFromPath($path) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getEngineFromPath($path); + } + + /** + * Add a piece of shared data to the environment. + * + * @param array|string $key + * @param mixed|null $value + * @return mixed + * @static + */ + public static function share($key, $value = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->share($key, $value); + } + + /** + * Increment the rendering counter. + * + * @return void + * @static + */ + public static function incrementRender() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->incrementRender(); + } + + /** + * Decrement the rendering counter. + * + * @return void + * @static + */ + public static function decrementRender() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->decrementRender(); + } + + /** + * Check if there are no active render operations. + * + * @return bool + * @static + */ + public static function doneRendering() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->doneRendering(); + } + + /** + * Determine if the given once token has been rendered. + * + * @param string $id + * @return bool + * @static + */ + public static function hasRenderedOnce($id) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->hasRenderedOnce($id); + } + + /** + * Mark the given once token as having been rendered. + * + * @param string $id + * @return void + * @static + */ + public static function markAsRenderedOnce($id) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->markAsRenderedOnce($id); + } + + /** + * Add a location to the array of view locations. + * + * @param string $location + * @return void + * @static + */ + public static function addLocation($location) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->addLocation($location); + } + + /** + * Prepend a location to the array of view locations. + * + * @param string $location + * @return void + * @static + */ + public static function prependLocation($location) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->prependLocation($location); + } + + /** + * Add a new namespace to the loader. + * + * @param string $namespace + * @param string|array $hints + * @return \Illuminate\View\Factory + * @static + */ + public static function addNamespace($namespace, $hints) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->addNamespace($namespace, $hints); + } + + /** + * Prepend a new namespace to the loader. + * + * @param string $namespace + * @param string|array $hints + * @return \Illuminate\View\Factory + * @static + */ + public static function prependNamespace($namespace, $hints) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->prependNamespace($namespace, $hints); + } + + /** + * Replace the namespace hints for the given namespace. + * + * @param string $namespace + * @param string|array $hints + * @return \Illuminate\View\Factory + * @static + */ + public static function replaceNamespace($namespace, $hints) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->replaceNamespace($namespace, $hints); + } + + /** + * Register a valid view extension and its engine. + * + * @param string $extension + * @param string $engine + * @param \Closure|null $resolver + * @return void + * @static + */ + public static function addExtension($extension, $engine, $resolver = null) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->addExtension($extension, $engine, $resolver); + } + + /** + * Flush all of the factory state like sections and stacks. + * + * @return void + * @static + */ + public static function flushState() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushState(); + } + + /** + * Flush all of the section contents if done rendering. + * + * @return void + * @static + */ + public static function flushStateIfDoneRendering() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushStateIfDoneRendering(); + } + + /** + * Get the extension to engine bindings. + * + * @return array + * @static + */ + public static function getExtensions() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getExtensions(); + } + + /** + * Get the engine resolver instance. + * + * @return \Illuminate\View\Engines\EngineResolver + * @static + */ + public static function getEngineResolver() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getEngineResolver(); + } + + /** + * Get the view finder instance. + * + * @return \Illuminate\View\ViewFinderInterface + * @static + */ + public static function getFinder() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getFinder(); + } + + /** + * Set the view finder instance. + * + * @param \Illuminate\View\ViewFinderInterface $finder + * @return void + * @static + */ + public static function setFinder($finder) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->setFinder($finder); + } + + /** + * Flush the cache of views located by the finder. + * + * @return void + * @static + */ + public static function flushFinderCache() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushFinderCache(); + } + + /** + * Get the event dispatcher instance. + * + * @return \Illuminate\Contracts\Events\Dispatcher + * @static + */ + public static function getDispatcher() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getDispatcher(); + } + + /** + * Set the event dispatcher instance. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + * @static + */ + public static function setDispatcher($events) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->setDispatcher($events); + } + + /** + * Get the IoC container instance. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getContainer(); + } + + /** + * Set the IoC container instance. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return void + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->setContainer($container); + } + + /** + * Get an item from the shared data. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function shared($key, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->shared($key, $default); + } + + /** + * Get all of the shared data for the environment. + * + * @return array + * @static + */ + public static function getShared() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getShared(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\View\Factory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\View\Factory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\View\Factory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\View\Factory::flushMacros(); + } + + /** + * Start a component rendering process. + * + * @param \Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string $view + * @param array $data + * @return void + * @static + */ + public static function startComponent($view, $data = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startComponent($view, $data); + } + + /** + * Get the first view that actually exists from the given list, and start a component. + * + * @param array $names + * @param array $data + * @return void + * @static + */ + public static function startComponentFirst($names, $data = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startComponentFirst($names, $data); + } + + /** + * Render the current component. + * + * @return string + * @static + */ + public static function renderComponent() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderComponent(); + } + + /** + * Get an item from the component data that exists above the current component. + * + * @param string $key + * @param mixed $default + * @return mixed|null + * @static + */ + public static function getConsumableComponentData($key, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getConsumableComponentData($key, $default); + } + + /** + * Start the slot rendering process. + * + * @param string $name + * @param string|null $content + * @param array $attributes + * @return void + * @static + */ + public static function slot($name, $content = null, $attributes = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->slot($name, $content, $attributes); + } + + /** + * Save the slot content for rendering. + * + * @return void + * @static + */ + public static function endSlot() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->endSlot(); + } + + /** + * Register a view creator event. + * + * @param array|string $views + * @param \Closure|string $callback + * @return array + * @static + */ + public static function creator($views, $callback) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->creator($views, $callback); + } + + /** + * Register multiple view composers via an array. + * + * @param array $composers + * @return array + * @static + */ + public static function composers($composers) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->composers($composers); + } + + /** + * Register a view composer event. + * + * @param array|string $views + * @param \Closure|string $callback + * @return array + * @static + */ + public static function composer($views, $callback) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->composer($views, $callback); + } + + /** + * Call the composer for a given view. + * + * @param \Illuminate\Contracts\View\View $view + * @return void + * @static + */ + public static function callComposer($view) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->callComposer($view); + } + + /** + * Call the creator for a given view. + * + * @param \Illuminate\Contracts\View\View $view + * @return void + * @static + */ + public static function callCreator($view) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->callCreator($view); + } + + /** + * Start injecting content into a fragment. + * + * @param string $fragment + * @return void + * @static + */ + public static function startFragment($fragment) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startFragment($fragment); + } + + /** + * Stop injecting content into a fragment. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopFragment() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopFragment(); + } + + /** + * Get the contents of a fragment. + * + * @param string $name + * @param string|null $default + * @return mixed + * @static + */ + public static function getFragment($name, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getFragment($name, $default); + } + + /** + * Get the entire array of rendered fragments. + * + * @return array + * @static + */ + public static function getFragments() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getFragments(); + } + + /** + * Flush all of the fragments. + * + * @return void + * @static + */ + public static function flushFragments() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushFragments(); + } + + /** + * Start injecting content into a section. + * + * @param string $section + * @param string|null $content + * @return void + * @static + */ + public static function startSection($section, $content = null) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startSection($section, $content); + } + + /** + * Inject inline content into a section. + * + * @param string $section + * @param string $content + * @return void + * @static + */ + public static function inject($section, $content) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->inject($section, $content); + } + + /** + * Stop injecting content into a section and return its contents. + * + * @return string + * @static + */ + public static function yieldSection() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->yieldSection(); + } + + /** + * Stop injecting content into a section. + * + * @param bool $overwrite + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopSection($overwrite = false) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopSection($overwrite); + } + + /** + * Stop injecting content into a section and append it. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function appendSection() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->appendSection(); + } + + /** + * Get the string contents of a section. + * + * @param string $section + * @param string $default + * @return string + * @static + */ + public static function yieldContent($section, $default = '') + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->yieldContent($section, $default); + } + + /** + * Get the parent placeholder for the current request. + * + * @param string $section + * @return string + * @static + */ + public static function parentPlaceholder($section = '') + { + return \Illuminate\View\Factory::parentPlaceholder($section); + } + + /** + * Check if section exists. + * + * @param string $name + * @return bool + * @static + */ + public static function hasSection($name) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->hasSection($name); + } + + /** + * Check if section does not exist. + * + * @param string $name + * @return bool + * @static + */ + public static function sectionMissing($name) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->sectionMissing($name); + } + + /** + * Get the contents of a section. + * + * @param string $name + * @param string|null $default + * @return mixed + * @static + */ + public static function getSection($name, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getSection($name, $default); + } + + /** + * Get the entire array of sections. + * + * @return array + * @static + */ + public static function getSections() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getSections(); + } + + /** + * Flush all of the sections. + * + * @return void + * @static + */ + public static function flushSections() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushSections(); + } + + /** + * Add new loop to the stack. + * + * @param \Countable|array $data + * @return void + * @static + */ + public static function addLoop($data) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->addLoop($data); + } + + /** + * Increment the top loop's indices. + * + * @return void + * @static + */ + public static function incrementLoopIndices() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->incrementLoopIndices(); + } + + /** + * Pop a loop from the top of the loop stack. + * + * @return void + * @static + */ + public static function popLoop() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->popLoop(); + } + + /** + * Get an instance of the last loop in the stack. + * + * @return \stdClass|null + * @static + */ + public static function getLastLoop() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getLastLoop(); + } + + /** + * Get the entire loop stack. + * + * @return array + * @static + */ + public static function getLoopStack() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getLoopStack(); + } + + /** + * Start injecting content into a push section. + * + * @param string $section + * @param string $content + * @return void + * @static + */ + public static function startPush($section, $content = '') + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startPush($section, $content); + } + + /** + * Stop injecting content into a push section. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopPush() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopPush(); + } + + /** + * Start prepending content into a push section. + * + * @param string $section + * @param string $content + * @return void + * @static + */ + public static function startPrepend($section, $content = '') + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startPrepend($section, $content); + } + + /** + * Stop prepending content into a push section. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopPrepend() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopPrepend(); + } + + /** + * Get the string contents of a push section. + * + * @param string $section + * @param string $default + * @return string + * @static + */ + public static function yieldPushContent($section, $default = '') + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->yieldPushContent($section, $default); + } + + /** + * Flush all of the stacks. + * + * @return void + * @static + */ + public static function flushStacks() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushStacks(); + } + + /** + * Start a translation block. + * + * @param array $replacements + * @return void + * @static + */ + public static function startTranslation($replacements = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startTranslation($replacements); + } + + /** + * Render the current translation. + * + * @return string + * @static + */ + public static function renderTranslation() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderTranslation(); + } + + } + /** + * + * + * @see \Illuminate\Foundation\Vite + */ + class Vite { + /** + * Get the preloaded assets. + * + * @return array + * @static + */ + public static function preloadedAssets() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->preloadedAssets(); + } + + /** + * Get the Content Security Policy nonce applied to all generated tags. + * + * @return string|null + * @static + */ + public static function cspNonce() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->cspNonce(); + } + + /** + * Generate or set a Content Security Policy nonce to apply to all generated tags. + * + * @param string|null $nonce + * @return string + * @static + */ + public static function useCspNonce($nonce = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useCspNonce($nonce); + } + + /** + * Use the given key to detect integrity hashes in the manifest. + * + * @param string|false $key + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useIntegrityKey($key) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useIntegrityKey($key); + } + + /** + * Set the Vite entry points. + * + * @param array $entryPoints + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function withEntryPoints($entryPoints) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->withEntryPoints($entryPoints); + } + + /** + * Merge additional Vite entry points with the current set. + * + * @param array $entryPoints + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function mergeEntryPoints($entryPoints) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->mergeEntryPoints($entryPoints); + } + + /** + * Set the filename for the manifest file. + * + * @param string $filename + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useManifestFilename($filename) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useManifestFilename($filename); + } + + /** + * Resolve asset paths using the provided resolver. + * + * @param callable|null $resolver + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function createAssetPathsUsing($resolver) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->createAssetPathsUsing($resolver); + } + + /** + * Get the Vite "hot" file path. + * + * @return string + * @static + */ + public static function hotFile() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->hotFile(); + } + + /** + * Set the Vite "hot" file path. + * + * @param string $path + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useHotFile($path) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useHotFile($path); + } + + /** + * Set the Vite build directory. + * + * @param string $path + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useBuildDirectory($path) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useBuildDirectory($path); + } + + /** + * Use the given callback to resolve attributes for script tags. + * + * @param (callable(string, string, ?array, ?array): array)|array $attributes + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useScriptTagAttributes($attributes) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useScriptTagAttributes($attributes); + } + + /** + * Use the given callback to resolve attributes for style tags. + * + * @param (callable(string, string, ?array, ?array): array)|array $attributes + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useStyleTagAttributes($attributes) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useStyleTagAttributes($attributes); + } + + /** + * Use the given callback to resolve attributes for preload tags. + * + * @param (callable(string, string, ?array, ?array): (array|false))|array|false $attributes + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function usePreloadTagAttributes($attributes) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->usePreloadTagAttributes($attributes); + } + + /** + * Eagerly prefetch assets. + * + * @param int|null $concurrency + * @param string $event + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function prefetch($concurrency = null, $event = 'load') + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->prefetch($concurrency, $event); + } + + /** + * Use the "waterfall" prefetching strategy. + * + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useWaterfallPrefetching($concurrency = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useWaterfallPrefetching($concurrency); + } + + /** + * Use the "aggressive" prefetching strategy. + * + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useAggressivePrefetching() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useAggressivePrefetching(); + } + + /** + * Set the prefetching strategy. + * + * @param 'waterfall'|'aggressive'|null $strategy + * @param array $config + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function usePrefetchStrategy($strategy, $config = []) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->usePrefetchStrategy($strategy, $config); + } + + /** + * Generate React refresh runtime script. + * + * @return \Illuminate\Support\HtmlString|void + * @static + */ + public static function reactRefresh() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->reactRefresh(); + } + + /** + * Get the URL for an asset. + * + * @param string $asset + * @param string|null $buildDirectory + * @return string + * @static + */ + public static function asset($asset, $buildDirectory = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->asset($asset, $buildDirectory); + } + + /** + * Get the content of a given asset. + * + * @param string $asset + * @param string|null $buildDirectory + * @return string + * @throws \Illuminate\Foundation\ViteException + * @static + */ + public static function content($asset, $buildDirectory = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->content($asset, $buildDirectory); + } + + /** + * Get a unique hash representing the current manifest, or null if there is no manifest. + * + * @param string|null $buildDirectory + * @return string|null + * @static + */ + public static function manifestHash($buildDirectory = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->manifestHash($buildDirectory); + } + + /** + * Determine if the HMR server is running. + * + * @return bool + * @static + */ + public static function isRunningHot() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->isRunningHot(); + } + + /** + * Get the Vite tag content as a string of HTML. + * + * @return string + * @static + */ + public static function toHtml() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->toHtml(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Foundation\Vite::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Foundation\Vite::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Foundation\Vite::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Foundation\Vite::flushMacros(); + } + + } + } + +namespace Illuminate\Http { + /** + * + * + */ + class Request { + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestValidation() + * @param array $rules + * @param mixed $params + * @static + */ + public static function validate($rules, ...$params) + { + return \Illuminate\Http\Request::validate($rules, ...$params); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestValidation() + * @param string $errorBag + * @param array $rules + * @param mixed $params + * @static + */ + public static function validateWithBag($errorBag, $rules, ...$params) + { + return \Illuminate\Http\Request::validateWithBag($errorBag, $rules, ...$params); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @param mixed $absolute + * @static + */ + public static function hasValidSignature($absolute = true) + { + return \Illuminate\Http\Request::hasValidSignature($absolute); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @static + */ + public static function hasValidRelativeSignature() + { + return \Illuminate\Http\Request::hasValidRelativeSignature(); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @param mixed $ignoreQuery + * @param mixed $absolute + * @static + */ + public static function hasValidSignatureWhileIgnoring($ignoreQuery = [], $absolute = true) + { + return \Illuminate\Http\Request::hasValidSignatureWhileIgnoring($ignoreQuery, $absolute); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @param mixed $ignoreQuery + * @static + */ + public static function hasValidRelativeSignatureWhileIgnoring($ignoreQuery = []) + { + return \Illuminate\Http\Request::hasValidRelativeSignatureWhileIgnoring($ignoreQuery); + } + + } + } + + +namespace { + class App extends \Illuminate\Support\Facades\App {} + class Arr extends \Illuminate\Support\Arr {} + class Artisan extends \Illuminate\Support\Facades\Artisan {} + class Auth extends \Illuminate\Support\Facades\Auth {} + class Blade extends \Illuminate\Support\Facades\Blade {} + class Broadcast extends \Illuminate\Support\Facades\Broadcast {} + class Bus extends \Illuminate\Support\Facades\Bus {} + class Cache extends \Illuminate\Support\Facades\Cache {} + class Config extends \Illuminate\Support\Facades\Config {} + class Context extends \Illuminate\Support\Facades\Context {} + class Cookie extends \Illuminate\Support\Facades\Cookie {} + class Crypt extends \Illuminate\Support\Facades\Crypt {} + class Date extends \Illuminate\Support\Facades\Date {} + class DB extends \Illuminate\Support\Facades\DB {} + + /** + * + * + * @template TCollection of static + * @template TModel of static + * @template TValue of static + * @template TValue of static + */ + class Eloquent extends \Illuminate\Database\Eloquent\Model { /** + * Create and return an un-saved model instance. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function make($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->make($attributes); + } + + /** + * Register a new global scope. + * + * @param string $identifier + * @param \Illuminate\Database\Eloquent\Scope|\Closure $scope + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withGlobalScope($identifier, $scope) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withGlobalScope($identifier, $scope); + } + + /** + * Remove a registered global scope. + * + * @param \Illuminate\Database\Eloquent\Scope|string $scope + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutGlobalScope($scope) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutGlobalScope($scope); + } + + /** + * Remove all or passed registered global scopes. + * + * @param array|null $scopes + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutGlobalScopes($scopes = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutGlobalScopes($scopes); + } + + /** + * Get an array of global scopes that were removed from the query. + * + * @return array + * @static + */ + public static function removedScopes() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->removedScopes(); + } + + /** + * Add a where clause on the primary key to the query. + * + * @param mixed $id + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereKey($id) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereKey($id); + } + + /** + * Add a where clause on the primary key to the query. + * + * @param mixed $id + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereKeyNot($id) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereKeyNot($id); + } + + /** + * Add a basic where clause to the query. + * + * @param (\Closure(static): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function where($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->where($column, $operator, $value, $boolean); + } + + /** + * Add a basic where clause to the query, and return the first result. + * + * @param (\Closure(static): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return TModel|null + * @static + */ + public static function firstWhere($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstWhere($column, $operator, $value, $boolean); + } + + /** + * Add an "or where" clause to the query. + * + * @param (\Closure(static): mixed)|array|string|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhere($column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhere($column, $operator, $value); + } + + /** + * Add a basic "where not" clause to the query. + * + * @param (\Closure(static): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNot($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereNot($column, $operator, $value, $boolean); + } + + /** + * Add an "or where not" clause to the query. + * + * @param (\Closure(static): mixed)|array|string|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNot($column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereNot($column, $operator, $value); + } + + /** + * Add an "order by" clause for a timestamp to the query. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function latest($column = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->latest($column); + } + + /** + * Add an "order by" clause for a timestamp to the query. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function oldest($column = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->oldest($column); + } + + /** + * Create a collection of models from plain arrays. + * + * @param array $items + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function hydrate($items) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->hydrate($items); + } + + /** + * Create a collection of models from a raw query. + * + * @param string $query + * @param array $bindings + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function fromQuery($query, $bindings = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->fromQuery($query, $bindings); + } + + /** + * Find a model by its primary key. + * + * @param mixed $id + * @param array|string $columns + * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TModel|null) + * @static + */ + public static function find($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->find($id, $columns); + } + + /** + * Find a sole model by its primary key. + * + * @param mixed $id + * @param array|string $columns + * @return TModel + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function findSole($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findSole($id, $columns); + } + + /** + * Find multiple models by their primary keys. + * + * @param \Illuminate\Contracts\Support\Arrayable|array $ids + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function findMany($ids, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findMany($ids, $columns); + } + + /** + * Find a model by its primary key or throw an exception. + * + * @param mixed $id + * @param array|string $columns + * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TModel) + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @static + */ + public static function findOrFail($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findOrFail($id, $columns); + } + + /** + * Find a model by its primary key or return fresh model instance. + * + * @param mixed $id + * @param array|string $columns + * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TModel) + * @static + */ + public static function findOrNew($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findOrNew($id, $columns); + } + + /** + * Find a model by its primary key or call a callback. + * + * @template TValue + * @param mixed $id + * @param (\Closure(): TValue)|list|string $columns + * @param (\Closure(): TValue)|null $callback + * @return ( $id is (\Illuminate\Contracts\Support\Arrayable|array) + * ? \Illuminate\Database\Eloquent\Collection + * : TModel|TValue + * ) + * @static + */ + public static function findOr($id, $columns = [], $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findOr($id, $columns, $callback); + } + + /** + * Get the first record matching the attributes or instantiate it. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function firstOrNew($attributes = [], $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOrNew($attributes, $values); + } + + /** + * Get the first record matching the attributes. If the record is not found, create it. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function firstOrCreate($attributes = [], $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOrCreate($attributes, $values); + } + + /** + * Attempt to create the record. If a unique constraint violation occurs, attempt to find the matching record. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function createOrFirst($attributes = [], $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->createOrFirst($attributes, $values); + } + + /** + * Create or update a record matching the attributes, and fill it with values. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function updateOrCreate($attributes, $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->updateOrCreate($attributes, $values); + } + + /** + * Create a record matching the attributes, or increment the existing record. + * + * @param array $attributes + * @param string $column + * @param int|float $default + * @param int|float $step + * @param array $extra + * @return TModel + * @static + */ + public static function incrementOrCreate($attributes, $column = 'count', $default = 1, $step = 1, $extra = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->incrementOrCreate($attributes, $column, $default, $step, $extra); + } + + /** + * Execute the query and get the first result or throw an exception. + * + * @param array|string $columns + * @return TModel + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @static + */ + public static function firstOrFail($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOrFail($columns); + } + + /** + * Execute the query and get the first result or call a callback. + * + * @template TValue + * @param (\Closure(): TValue)|list $columns + * @param (\Closure(): TValue)|null $callback + * @return TModel|TValue + * @static + */ + public static function firstOr($columns = [], $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOr($columns, $callback); + } + + /** + * Execute the query and get the first result if it's the sole matching record. + * + * @param array|string $columns + * @return TModel + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function sole($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->sole($columns); + } + + /** + * Get a single column's value from the first result of a query. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return mixed + * @static + */ + public static function value($column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->value($column); + } + + /** + * Get a single column's value from the first result of a query if it's the sole matching record. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return mixed + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function soleValue($column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->soleValue($column); + } + + /** + * Get a single column's value from the first result of the query or throw an exception. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return mixed + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @static + */ + public static function valueOrFail($column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->valueOrFail($column); + } + + /** + * Execute the query as a "select" statement. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function get($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->get($columns); + } + + /** + * Get the hydrated models without eager loading. + * + * @param array|string $columns + * @return array + * @static + */ + public static function getModels($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getModels($columns); + } + + /** + * Eager load the relationships for the models. + * + * @param array $models + * @return array + * @static + */ + public static function eagerLoadRelations($models) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->eagerLoadRelations($models); + } + + /** + * Register a closure to be invoked after the query is executed. + * + * @param \Closure $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function afterQuery($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->afterQuery($callback); + } + + /** + * Invoke the "after query" modification callbacks. + * + * @param mixed $result + * @return mixed + * @static + */ + public static function applyAfterQueryCallbacks($result) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->applyAfterQueryCallbacks($result); + } + + /** + * Get a lazy collection for the given query. + * + * @return \Illuminate\Support\LazyCollection + * @static + */ + public static function cursor() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->cursor(); + } + + /** + * Get a collection with the values of a given column. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @param string|null $key + * @return \Illuminate\Support\Collection + * @static + */ + public static function pluck($column, $key = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->pluck($column, $key); + } + + /** + * Paginate the given query. + * + * @param int|null|\Closure $perPage + * @param array|string $columns + * @param string $pageName + * @param int|null $page + * @param \Closure|int|null $total + * @return \Illuminate\Pagination\LengthAwarePaginator + * @throws \InvalidArgumentException + * @static + */ + public static function paginate($perPage = null, $columns = [], $pageName = 'page', $page = null, $total = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->paginate($perPage, $columns, $pageName, $page, $total); + } + + /** + * Paginate the given query into a simple paginator. + * + * @param int|null $perPage + * @param array|string $columns + * @param string $pageName + * @param int|null $page + * @return \Illuminate\Contracts\Pagination\Paginator + * @static + */ + public static function simplePaginate($perPage = null, $columns = [], $pageName = 'page', $page = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->simplePaginate($perPage, $columns, $pageName, $page); + } + + /** + * Paginate the given query into a cursor paginator. + * + * @param int|null $perPage + * @param array|string $columns + * @param string $cursorName + * @param \Illuminate\Pagination\Cursor|string|null $cursor + * @return \Illuminate\Contracts\Pagination\CursorPaginator + * @static + */ + public static function cursorPaginate($perPage = null, $columns = [], $cursorName = 'cursor', $cursor = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->cursorPaginate($perPage, $columns, $cursorName, $cursor); + } + + /** + * Save a new model and return the instance. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function create($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->create($attributes); + } + + /** + * Save a new model and return the instance without raising model events. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function createQuietly($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->createQuietly($attributes); + } + + /** + * Save a new model and return the instance. Allow mass-assignment. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function forceCreate($attributes) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->forceCreate($attributes); + } + + /** + * Save a new model instance with mass assignment without raising model events. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function forceCreateQuietly($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->forceCreateQuietly($attributes); + } + + /** + * Insert new records or update the existing ones. + * + * @param array $values + * @param array|string $uniqueBy + * @param array|null $update + * @return int + * @static + */ + public static function upsert($values, $uniqueBy, $update = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->upsert($values, $uniqueBy, $update); + } + + /** + * Register a replacement for the default delete function. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function onDelete($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + $instance->onDelete($callback); + } + + /** + * Call the given local model scopes. + * + * @param array|string $scopes + * @return static|mixed + * @static + */ + public static function scopes($scopes) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->scopes($scopes); + } + + /** + * Apply the scopes to the Eloquent builder instance and return it. + * + * @return static + * @static + */ + public static function applyScopes() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->applyScopes(); + } + + /** + * Prevent the specified relations from being eager loaded. + * + * @param mixed $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function without($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->without($relations); + } + + /** + * Set the relationships that should be eager loaded while removing any previously added eager loading specifications. + * + * @param array): mixed)|string>|string $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withOnly($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withOnly($relations); + } + + /** + * Create a new instance of the model being queried. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function newModelInstance($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->newModelInstance($attributes); + } + + /** + * Specify attributes that should be added to any new models created by this builder. + * + * The given key / value pairs will also be added as where conditions to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|array|string $attributes + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withAttributes($attributes, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withAttributes($attributes, $value); + } + + /** + * Apply query-time casts to the model instance. + * + * @param array $casts + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withCasts($casts) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withCasts($casts); + } + + /** + * Execute the given Closure within a transaction savepoint if needed. + * + * @template TModelValue + * @param \Closure(): TModelValue $scope + * @return TModelValue + * @static + */ + public static function withSavepointIfNeeded($scope) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withSavepointIfNeeded($scope); + } + + /** + * Get the underlying query builder instance. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function getQuery() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getQuery(); + } + + /** + * Set the underlying query builder instance. + * + * @param \Illuminate\Database\Query\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function setQuery($query) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->setQuery($query); + } + + /** + * Get a base query builder instance. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function toBase() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->toBase(); + } + + /** + * Get the relationships being eagerly loaded. + * + * @return array + * @static + */ + public static function getEagerLoads() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getEagerLoads(); + } + + /** + * Set the relationships being eagerly loaded. + * + * @param array $eagerLoad + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function setEagerLoads($eagerLoad) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->setEagerLoads($eagerLoad); + } + + /** + * Indicate that the given relationships should not be eagerly loaded. + * + * @param array $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutEagerLoad($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutEagerLoad($relations); + } + + /** + * Flush the relationships being eagerly loaded. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutEagerLoads() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutEagerLoads(); + } + + /** + * Get the "limit" value from the query or null if it's not set. + * + * @return mixed + * @static + */ + public static function getLimit() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getLimit(); + } + + /** + * Get the "offset" value from the query or null if it's not set. + * + * @return mixed + * @static + */ + public static function getOffset() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getOffset(); + } + + /** + * Get the model instance being queried. + * + * @return TModel + * @static + */ + public static function getModel() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getModel(); + } + + /** + * Set a model instance for the model being queried. + * + * @template TModelNew of \Illuminate\Database\Eloquent\Model + * @param TModelNew $model + * @return static + * @static + */ + public static function setModel($model) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->setModel($model); + } + + /** + * Get the given macro by name. + * + * @param string $name + * @return \Closure + * @static + */ + public static function getMacro($name) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getMacro($name); + } + + /** + * Checks if a macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->hasMacro($name); + } + + /** + * Get the given global macro by name. + * + * @param string $name + * @return \Closure + * @static + */ + public static function getGlobalMacro($name) + { + return \Illuminate\Database\Eloquent\Builder::getGlobalMacro($name); + } + + /** + * Checks if a global macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasGlobalMacro($name) + { + return \Illuminate\Database\Eloquent\Builder::hasGlobalMacro($name); + } + + /** + * Clone the Eloquent query builder. + * + * @return static + * @static + */ + public static function clone() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->clone(); + } + + /** + * Register a closure to be invoked on a clone. + * + * @param \Closure $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function onClone($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->onClone($callback); + } + + /** + * Chunk the results of the query. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @return bool + * @static + */ + public static function chunk($count, $callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunk($count, $callback); + } + + /** + * Run a map over each item while chunking. + * + * @template TReturn + * @param callable(TValue): TReturn $callback + * @param int $count + * @return \Illuminate\Support\Collection + * @static + */ + public static function chunkMap($callback, $count = 1000) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunkMap($callback, $count); + } + + /** + * Execute a callback over each item while chunking. + * + * @param callable(TValue, int): mixed $callback + * @param int $count + * @return bool + * @throws \RuntimeException + * @static + */ + public static function each($callback, $count = 1000) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->each($callback, $count); + } + + /** + * Chunk the results of a query by comparing IDs. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @param string|null $column + * @param string|null $alias + * @return bool + * @static + */ + public static function chunkById($count, $callback, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunkById($count, $callback, $column, $alias); + } + + /** + * Chunk the results of a query by comparing IDs in descending order. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @param string|null $column + * @param string|null $alias + * @return bool + * @static + */ + public static function chunkByIdDesc($count, $callback, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunkByIdDesc($count, $callback, $column, $alias); + } + + /** + * Chunk the results of a query by comparing IDs in a given order. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @param string|null $column + * @param string|null $alias + * @param bool $descending + * @return bool + * @throws \RuntimeException + * @static + */ + public static function orderedChunkById($count, $callback, $column = null, $alias = null, $descending = false) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orderedChunkById($count, $callback, $column, $alias, $descending); + } + + /** + * Execute a callback over each item while chunking by ID. + * + * @param callable(TValue, int): mixed $callback + * @param int $count + * @param string|null $column + * @param string|null $alias + * @return bool + * @static + */ + public static function eachById($callback, $count = 1000, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->eachById($callback, $count, $column, $alias); + } + + /** + * Query lazily, by chunks of the given size. + * + * @param int $chunkSize + * @return \Illuminate\Support\LazyCollection + * @throws \InvalidArgumentException + * @static + */ + public static function lazy($chunkSize = 1000) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->lazy($chunkSize); + } + + /** + * Query lazily, by chunking the results of a query by comparing IDs. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + * @throws \InvalidArgumentException + * @static + */ + public static function lazyById($chunkSize = 1000, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->lazyById($chunkSize, $column, $alias); + } + + /** + * Query lazily, by chunking the results of a query by comparing IDs in descending order. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + * @throws \InvalidArgumentException + * @static + */ + public static function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->lazyByIdDesc($chunkSize, $column, $alias); + } + + /** + * Execute the query and get the first result. + * + * @param array|string $columns + * @return TValue|null + * @static + */ + public static function first($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->first($columns); + } + + /** + * Execute the query and get the first result if it's the sole matching record. + * + * @param array|string $columns + * @return TValue + * @throws \Illuminate\Database\RecordsNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function baseSole($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->baseSole($columns); + } + + /** + * Pass the query to a given callback. + * + * @param callable($this): mixed $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function tap($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->tap($callback); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Add a relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param string $operator + * @param int $count + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @throws \RuntimeException + * @static + */ + public static function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->has($relation, $operator, $count, $boolean, $callback); + } + + /** + * Add a relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\Relation<*, *, *>|string $relation + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHas($relation, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orHas($relation, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function doesntHave($relation, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->doesntHave($relation, $boolean, $callback); + } + + /** + * Add a relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\Relation<*, *, *>|string $relation + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orDoesntHave($relation) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orDoesntHave($relation); + } + + /** + * Add a relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereHas($relation, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereHas($relation, $callback, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query with where clauses. + * + * Also load the relationship with the same condition. + * + * @param string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Database\Eloquent\Relations\Relation<*, *, *>): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withWhereHas($relation, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withWhereHas($relation, $callback, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereHas($relation, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereHas($relation, $callback, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDoesntHave($relation, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereDoesntHave($relation, $callback); + } + + /** + * Add a relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDoesntHave($relation, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereDoesntHave($relation, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param string $operator + * @param int $count + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->hasMorph($relation, $types, $operator, $count, $boolean, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param string|array $types + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHasMorph($relation, $types, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orHasMorph($relation, $types, $operator, $count); + } + + /** + * Add a polymorphic relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function doesntHaveMorph($relation, $types, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->doesntHaveMorph($relation, $types, $boolean, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param string|array $types + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orDoesntHaveMorph($relation, $types) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orDoesntHaveMorph($relation, $types); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereHasMorph($relation, $types, $callback, $operator, $count); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereHasMorph($relation, $types, $callback, $operator, $count); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDoesntHaveMorph($relation, $types, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereDoesntHaveMorph($relation, $types, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDoesntHaveMorph($relation, $types, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereDoesntHaveMorph($relation, $types, $callback); + } + + /** + * Add a basic where clause to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereRelation($relation, $column, $operator, $value); + } + + /** + * Add a basic where clause to a relationship query and eager-load the relationship with the same conditions. + * + * @param \Illuminate\Database\Eloquent\Relations\Relation<*, *, *>|string $relation + * @param \Closure|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withWhereRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withWhereRelation($relation, $column, $operator, $value); + } + + /** + * Add an "or where" clause to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereRelation($relation, $column, $operator, $value); + } + + /** + * Add a basic count / exists condition to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDoesntHaveRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereDoesntHaveRelation($relation, $column, $operator, $value); + } + + /** + * Add an "or where" clause to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDoesntHaveRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereDoesntHaveRelation($relation, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with a where clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMorphRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereMorphRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with an "or where" clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMorphRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereMorphRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with a doesn't have clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMorphDoesntHaveRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereMorphDoesntHaveRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with an "or doesn't have" clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMorphDoesntHaveRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereMorphDoesntHaveRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a morph-to relationship condition to the query. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string|null $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMorphedTo($relation, $model, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereMorphedTo($relation, $model, $boolean); + } + + /** + * Add a not morph-to relationship condition to the query. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotMorphedTo($relation, $model, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereNotMorphedTo($relation, $model, $boolean); + } + + /** + * Add a morph-to relationship condition to the query with an "or where" clause. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string|null $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMorphedTo($relation, $model) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereMorphedTo($relation, $model); + } + + /** + * Add a not morph-to relationship condition to the query with an "or where" clause. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotMorphedTo($relation, $model) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereNotMorphedTo($relation, $model); + } + + /** + * Add a "belongs to" relationship where clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection $related + * @param string|null $relationshipName + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @throws \Illuminate\Database\Eloquent\RelationNotFoundException + * @static + */ + public static function whereBelongsTo($related, $relationshipName = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereBelongsTo($related, $relationshipName, $boolean); + } + + /** + * Add a "BelongsTo" relationship with an "or where" clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model $related + * @param string|null $relationshipName + * @return \Illuminate\Database\Eloquent\Builder + * @throws \RuntimeException + * @static + */ + public static function orWhereBelongsTo($related, $relationshipName = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereBelongsTo($related, $relationshipName); + } + + /** + * Add subselect queries to include an aggregate value for a relationship. + * + * @param mixed $relations + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $function + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withAggregate($relations, $column, $function = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withAggregate($relations, $column, $function); + } + + /** + * Add subselect queries to count the relations. + * + * @param mixed $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withCount($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withCount($relations); + } + + /** + * Add subselect queries to include the max of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withMax($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withMax($relation, $column); + } + + /** + * Add subselect queries to include the min of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withMin($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withMin($relation, $column); + } + + /** + * Add subselect queries to include the sum of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withSum($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withSum($relation, $column); + } + + /** + * Add subselect queries to include the average of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withAvg($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withAvg($relation, $column); + } + + /** + * Add subselect queries to include the existence of related models. + * + * @param string|array $relation + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withExists($relation) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withExists($relation); + } + + /** + * Merge the where constraints from another query to the current query. + * + * @param \Illuminate\Database\Eloquent\Builder<*> $from + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function mergeConstraintsFrom($from) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->mergeConstraintsFrom($from); + } + + /** + * Set the columns to be selected. + * + * @param array|mixed $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function select($columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->select($columns); + } + + /** + * Add a subselect expression to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function selectSub($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->selectSub($query, $as); + } + + /** + * Add a new "raw" select expression to the query. + * + * @param string $expression + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function selectRaw($expression, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->selectRaw($expression, $bindings); + } + + /** + * Makes "from" fetch from a subquery. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function fromSub($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->fromSub($query, $as); + } + + /** + * Add a raw from clause to the query. + * + * @param string $expression + * @param mixed $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function fromRaw($expression, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->fromRaw($expression, $bindings); + } + + /** + * Add a new select column to the query. + * + * @param array|mixed $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addSelect($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addSelect($column); + } + + /** + * Force the query to only return distinct results. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function distinct() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->distinct(); + } + + /** + * Set the table which the query is targeting. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Contracts\Database\Query\Expression|string $table + * @param string|null $as + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function from($table, $as = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->from($table, $as); + } + + /** + * Add an index hint to suggest a query index. + * + * @param string $index + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function useIndex($index) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->useIndex($index); + } + + /** + * Add an index hint to force a query index. + * + * @param string $index + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forceIndex($index) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forceIndex($index); + } + + /** + * Add an index hint to ignore a query index. + * + * @param string $index + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function ignoreIndex($index) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->ignoreIndex($index); + } + + /** + * Add a join clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @param string $type + * @param bool $where + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->join($table, $first, $operator, $second, $type, $where); + } + + /** + * Add a "join where" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string $second + * @param string $type + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function joinWhere($table, $first, $operator, $second, $type = 'inner') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->joinWhere($table, $first, $operator, $second, $type); + } + + /** + * Add a subquery join clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @param string $type + * @param bool $where + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->joinSub($query, $as, $first, $operator, $second, $type, $where); + } + + /** + * Add a lateral join clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function joinLateral($query, $as, $type = 'inner') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->joinLateral($query, $as, $type); + } + + /** + * Add a lateral left join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoinLateral($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoinLateral($query, $as); + } + + /** + * Add a left join to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoin($table, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoin($table, $first, $operator, $second); + } + + /** + * Add a "join where" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoinWhere($table, $first, $operator, $second) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoinWhere($table, $first, $operator, $second); + } + + /** + * Add a subquery left join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoinSub($query, $as, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoinSub($query, $as, $first, $operator, $second); + } + + /** + * Add a right join to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function rightJoin($table, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rightJoin($table, $first, $operator, $second); + } + + /** + * Add a "right join where" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function rightJoinWhere($table, $first, $operator, $second) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rightJoinWhere($table, $first, $operator, $second); + } + + /** + * Add a subquery right join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function rightJoinSub($query, $as, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rightJoinSub($query, $as, $first, $operator, $second); + } + + /** + * Add a "cross join" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string|null $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function crossJoin($table, $first = null, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->crossJoin($table, $first, $operator, $second); + } + + /** + * Add a subquery cross join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function crossJoinSub($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->crossJoinSub($query, $as); + } + + /** + * Merge an array of where clauses and bindings. + * + * @param array $wheres + * @param array $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function mergeWheres($wheres, $bindings) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->mergeWheres($wheres, $bindings); + } + + /** + * Prepare the value and operator for a where clause. + * + * @param string $value + * @param string $operator + * @param bool $useDefault + * @return array + * @throws \InvalidArgumentException + * @static + */ + public static function prepareValueAndOperator($value, $operator, $useDefault = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->prepareValueAndOperator($value, $operator, $useDefault); + } + + /** + * Add a "where" clause comparing two columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string|array $first + * @param string|null $operator + * @param string|null $second + * @param string|null $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereColumn($first, $operator = null, $second = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereColumn($first, $operator, $second, $boolean); + } + + /** + * Add an "or where" clause comparing two columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string|array $first + * @param string|null $operator + * @param string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereColumn($first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereColumn($first, $operator, $second); + } + + /** + * Add a raw where clause to the query. + * + * @param string $sql + * @param mixed $bindings + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereRaw($sql, $bindings = [], $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereRaw($sql, $bindings, $boolean); + } + + /** + * Add a raw or where clause to the query. + * + * @param string $sql + * @param mixed $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereRaw($sql, $bindings); + } + + /** + * Add a "where like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereLike($column, $value, $caseSensitive = false, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereLike($column, $value, $caseSensitive, $boolean, $not); + } + + /** + * Add an "or where like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereLike($column, $value, $caseSensitive = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereLike($column, $value, $caseSensitive); + } + + /** + * Add a "where not like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotLike($column, $value, $caseSensitive = false, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotLike($column, $value, $caseSensitive, $boolean); + } + + /** + * Add an "or where not like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotLike($column, $value, $caseSensitive = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotLike($column, $value, $caseSensitive); + } + + /** + * Add a "where in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereIn($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereIn($column, $values, $boolean, $not); + } + + /** + * Add an "or where in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereIn($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereIn($column, $values); + } + + /** + * Add a "where not in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotIn($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotIn($column, $values, $boolean); + } + + /** + * Add an "or where not in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotIn($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotIn($column, $values); + } + + /** + * Add a "where in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereIntegerInRaw($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereIntegerInRaw($column, $values, $boolean, $not); + } + + /** + * Add an "or where in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereIntegerInRaw($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereIntegerInRaw($column, $values); + } + + /** + * Add a "where not in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereIntegerNotInRaw($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereIntegerNotInRaw($column, $values, $boolean); + } + + /** + * Add an "or where not in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereIntegerNotInRaw($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereIntegerNotInRaw($column, $values); + } + + /** + * Add a "where null" clause to the query. + * + * @param string|array|\Illuminate\Contracts\Database\Query\Expression $columns + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNull($columns, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNull($columns, $boolean, $not); + } + + /** + * Add an "or where null" clause to the query. + * + * @param string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNull($column); + } + + /** + * Add a "where not null" clause to the query. + * + * @param string|array|\Illuminate\Contracts\Database\Query\Expression $columns + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotNull($columns, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotNull($columns, $boolean); + } + + /** + * Add a where between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereBetween($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereBetween($column, $values, $boolean, $not); + } + + /** + * Add a where between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereBetweenColumns($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereBetweenColumns($column, $values, $boolean, $not); + } + + /** + * Add an or where between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereBetween($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereBetween($column, $values); + } + + /** + * Add an or where between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereBetweenColumns($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereBetweenColumns($column, $values); + } + + /** + * Add a where not between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotBetween($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotBetween($column, $values, $boolean); + } + + /** + * Add a where not between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotBetweenColumns($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotBetweenColumns($column, $values, $boolean); + } + + /** + * Add an or where not between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotBetween($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotBetween($column, $values); + } + + /** + * Add an or where not between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotBetweenColumns($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotBetweenColumns($column, $values); + } + + /** + * Add an "or where not null" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotNull($column); + } + + /** + * Add a "where date" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDate($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereDate($column, $operator, $value, $boolean); + } + + /** + * Add an "or where date" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDate($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereDate($column, $operator, $value); + } + + /** + * Add a "where time" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereTime($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereTime($column, $operator, $value, $boolean); + } + + /** + * Add an "or where time" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereTime($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereTime($column, $operator, $value); + } + + /** + * Add a "where day" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDay($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereDay($column, $operator, $value, $boolean); + } + + /** + * Add an "or where day" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDay($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereDay($column, $operator, $value); + } + + /** + * Add a "where month" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMonth($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereMonth($column, $operator, $value, $boolean); + } + + /** + * Add an "or where month" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMonth($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereMonth($column, $operator, $value); + } + + /** + * Add a "where year" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereYear($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereYear($column, $operator, $value, $boolean); + } + + /** + * Add an "or where year" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereYear($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereYear($column, $operator, $value); + } + + /** + * Add a nested where statement to the query. + * + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNested($callback, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNested($callback, $boolean); + } + + /** + * Create a new query instance for nested where condition. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function forNestedWhere() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forNestedWhere(); + } + + /** + * Add another query builder as a nested where to the query builder. + * + * @param \Illuminate\Database\Query\Builder $query + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addNestedWhereQuery($query, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addNestedWhereQuery($query, $boolean); + } + + /** + * Add an exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereExists($callback, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereExists($callback, $boolean, $not); + } + + /** + * Add an or exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereExists($callback, $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereExists($callback, $not); + } + + /** + * Add a where not exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotExists($callback, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotExists($callback, $boolean); + } + + /** + * Add a where not exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotExists($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotExists($callback); + } + + /** + * Add an exists clause to the query. + * + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addWhereExistsQuery($query, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addWhereExistsQuery($query, $boolean, $not); + } + + /** + * Adds a where condition using row values. + * + * @param array $columns + * @param string $operator + * @param array $values + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function whereRowValues($columns, $operator, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereRowValues($columns, $operator, $values, $boolean); + } + + /** + * Adds an or where condition using row values. + * + * @param array $columns + * @param string $operator + * @param array $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereRowValues($columns, $operator, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereRowValues($columns, $operator, $values); + } + + /** + * Add a "where JSON contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonContains($column, $value, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonContains($column, $value, $boolean, $not); + } + + /** + * Add an "or where JSON contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonContains($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonContains($column, $value); + } + + /** + * Add a "where JSON not contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonDoesntContain($column, $value, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonDoesntContain($column, $value, $boolean); + } + + /** + * Add an "or where JSON not contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonDoesntContain($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonDoesntContain($column, $value); + } + + /** + * Add a "where JSON overlaps" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonOverlaps($column, $value, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonOverlaps($column, $value, $boolean, $not); + } + + /** + * Add an "or where JSON overlaps" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonOverlaps($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonOverlaps($column, $value); + } + + /** + * Add a "where JSON not overlap" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonDoesntOverlap($column, $value, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonDoesntOverlap($column, $value, $boolean); + } + + /** + * Add an "or where JSON not overlap" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonDoesntOverlap($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonDoesntOverlap($column, $value); + } + + /** + * Add a clause that determines if a JSON path exists to the query. + * + * @param string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonContainsKey($column, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonContainsKey($column, $boolean, $not); + } + + /** + * Add an "or" clause that determines if a JSON path exists to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonContainsKey($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonContainsKey($column); + } + + /** + * Add a clause that determines if a JSON path does not exist to the query. + * + * @param string $column + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonDoesntContainKey($column, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonDoesntContainKey($column, $boolean); + } + + /** + * Add an "or" clause that determines if a JSON path does not exist to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonDoesntContainKey($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonDoesntContainKey($column); + } + + /** + * Add a "where JSON length" clause to the query. + * + * @param string $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonLength($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonLength($column, $operator, $value, $boolean); + } + + /** + * Add an "or where JSON length" clause to the query. + * + * @param string $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonLength($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonLength($column, $operator, $value); + } + + /** + * Handles dynamic "where" clauses to the query. + * + * @param string $method + * @param array $parameters + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function dynamicWhere($method, $parameters) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dynamicWhere($method, $parameters); + } + + /** + * Add a "where fulltext" clause to the query. + * + * @param string|string[] $columns + * @param string $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereFullText($columns, $value, $options = [], $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereFullText($columns, $value, $options, $boolean); + } + + /** + * Add a "or where fulltext" clause to the query. + * + * @param string|string[] $columns + * @param string $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereFullText($columns, $value, $options = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereFullText($columns, $value, $options); + } + + /** + * Add a "where" clause to the query for multiple columns with "and" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereAll($columns, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereAll($columns, $operator, $value, $boolean); + } + + /** + * Add an "or where" clause to the query for multiple columns with "and" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereAll($columns, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereAll($columns, $operator, $value); + } + + /** + * Add a "where" clause to the query for multiple columns with "or" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereAny($columns, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereAny($columns, $operator, $value, $boolean); + } + + /** + * Add an "or where" clause to the query for multiple columns with "or" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereAny($columns, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereAny($columns, $operator, $value); + } + + /** + * Add a "where not" clause to the query for multiple columns where none of the conditions should be true. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNone($columns, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNone($columns, $operator, $value, $boolean); + } + + /** + * Add an "or where not" clause to the query for multiple columns where none of the conditions should be true. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNone($columns, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNone($columns, $operator, $value); + } + + /** + * Add a "group by" clause to the query. + * + * @param array|\Illuminate\Contracts\Database\Query\Expression|string $groups + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function groupBy(...$groups) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->groupBy(...$groups); + } + + /** + * Add a raw groupBy clause to the query. + * + * @param string $sql + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function groupByRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->groupByRaw($sql, $bindings); + } + + /** + * Add a "having" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column + * @param \DateTimeInterface|string|int|float|null $operator + * @param \DateTimeInterface|string|int|float|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function having($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->having($column, $operator, $value, $boolean); + } + + /** + * Add an "or having" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column + * @param \DateTimeInterface|string|int|float|null $operator + * @param \DateTimeInterface|string|int|float|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHaving($column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHaving($column, $operator, $value); + } + + /** + * Add a nested having statement to the query. + * + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingNested($callback, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingNested($callback, $boolean); + } + + /** + * Add another query builder as a nested having to the query builder. + * + * @param \Illuminate\Database\Query\Builder $query + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addNestedHavingQuery($query, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addNestedHavingQuery($query, $boolean); + } + + /** + * Add a "having null" clause to the query. + * + * @param array|string $columns + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingNull($columns, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingNull($columns, $boolean, $not); + } + + /** + * Add an "or having null" clause to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHavingNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHavingNull($column); + } + + /** + * Add a "having not null" clause to the query. + * + * @param array|string $columns + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingNotNull($columns, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingNotNull($columns, $boolean); + } + + /** + * Add an "or having not null" clause to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHavingNotNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHavingNotNull($column); + } + + /** + * Add a "having between " clause to the query. + * + * @param string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingBetween($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingBetween($column, $values, $boolean, $not); + } + + /** + * Add a raw having clause to the query. + * + * @param string $sql + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingRaw($sql, $bindings = [], $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingRaw($sql, $bindings, $boolean); + } + + /** + * Add a raw or having clause to the query. + * + * @param string $sql + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHavingRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHavingRaw($sql, $bindings); + } + + /** + * Add an "order by" clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $direction + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function orderBy($column, $direction = 'asc') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orderBy($column, $direction); + } + + /** + * Add a descending "order by" clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orderByDesc($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orderByDesc($column); + } + + /** + * Put the query's results in random order. + * + * @param string|int $seed + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function inRandomOrder($seed = '') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->inRandomOrder($seed); + } + + /** + * Add a raw "order by" clause to the query. + * + * @param string $sql + * @param array $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orderByRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orderByRaw($sql, $bindings); + } + + /** + * Alias to set the "offset" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function skip($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->skip($value); + } + + /** + * Set the "offset" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function offset($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->offset($value); + } + + /** + * Alias to set the "limit" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function take($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->take($value); + } + + /** + * Set the "limit" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function limit($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->limit($value); + } + + /** + * Add a "group limit" clause to the query. + * + * @param int $value + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function groupLimit($value, $column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->groupLimit($value, $column); + } + + /** + * Set the limit and offset for a given page. + * + * @param int $page + * @param int $perPage + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forPage($page, $perPage = 15) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forPage($page, $perPage); + } + + /** + * Constrain the query to the previous "page" of results before a given ID. + * + * @param int $perPage + * @param int|null $lastId + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forPageBeforeId($perPage, $lastId, $column); + } + + /** + * Constrain the query to the next "page" of results after a given ID. + * + * @param int $perPage + * @param int|null $lastId + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forPageAfterId($perPage, $lastId, $column); + } + + /** + * Remove all existing orders and optionally add a new order. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Contracts\Database\Query\Expression|string|null $column + * @param string $direction + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function reorder($column = null, $direction = 'asc') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->reorder($column, $direction); + } + + /** + * Add a union statement to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $query + * @param bool $all + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function union($query, $all = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->union($query, $all); + } + + /** + * Add a union all statement to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function unionAll($query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->unionAll($query); + } + + /** + * Lock the selected rows in the table. + * + * @param string|bool $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function lock($value = true) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->lock($value); + } + + /** + * Lock the selected rows in the table for updating. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function lockForUpdate() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->lockForUpdate(); + } + + /** + * Share lock the selected rows in the table. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function sharedLock() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->sharedLock(); + } + + /** + * Register a closure to be invoked before the query is executed. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function beforeQuery($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->beforeQuery($callback); + } + + /** + * Invoke the "before query" modification callbacks. + * + * @return void + * @static + */ + public static function applyBeforeQueryCallbacks() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + $instance->applyBeforeQueryCallbacks(); + } + + /** + * Get the SQL representation of the query. + * + * @return string + * @static + */ + public static function toSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->toSql(); + } + + /** + * Get the raw SQL representation of the query with embedded bindings. + * + * @return string + * @static + */ + public static function toRawSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->toRawSql(); + } + + /** + * Get a single expression value from the first result of a query. + * + * @return mixed + * @static + */ + public static function rawValue($expression, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rawValue($expression, $bindings); + } + + /** + * Get the count of the total records for the paginator. + * + * @param array $columns + * @return int + * @static + */ + public static function getCountForPagination($columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getCountForPagination($columns); + } + + /** + * Concatenate values of a given column as a string. + * + * @param string $column + * @param string $glue + * @return string + * @static + */ + public static function implode($column, $glue = '') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->implode($column, $glue); + } + + /** + * Determine if any rows exist for the current query. + * + * @return bool + * @static + */ + public static function exists() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->exists(); + } + + /** + * Determine if no rows exist for the current query. + * + * @return bool + * @static + */ + public static function doesntExist() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->doesntExist(); + } + + /** + * Execute the given callback if no rows exist for the current query. + * + * @return mixed + * @static + */ + public static function existsOr($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->existsOr($callback); + } + + /** + * Execute the given callback if rows exist for the current query. + * + * @return mixed + * @static + */ + public static function doesntExistOr($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->doesntExistOr($callback); + } + + /** + * Retrieve the "count" result of the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $columns + * @return int + * @static + */ + public static function count($columns = '*') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->count($columns); + } + + /** + * Retrieve the minimum value of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function min($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->min($column); + } + + /** + * Retrieve the maximum value of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function max($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->max($column); + } + + /** + * Retrieve the sum of the values of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function sum($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->sum($column); + } + + /** + * Retrieve the average of the values of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function avg($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->avg($column); + } + + /** + * Alias for the "avg" method. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function average($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->average($column); + } + + /** + * Execute an aggregate function on the database. + * + * @param string $function + * @param array $columns + * @return mixed + * @static + */ + public static function aggregate($function, $columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->aggregate($function, $columns); + } + + /** + * Execute a numeric aggregate function on the database. + * + * @param string $function + * @param array $columns + * @return float|int + * @static + */ + public static function numericAggregate($function, $columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->numericAggregate($function, $columns); + } + + /** + * Insert new records into the database. + * + * @return bool + * @static + */ + public static function insert($values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insert($values); + } + + /** + * Insert new records into the database while ignoring errors. + * + * @return int + * @static + */ + public static function insertOrIgnore($values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertOrIgnore($values); + } + + /** + * Insert a new record and get the value of the primary key. + * + * @param string|null $sequence + * @return int + * @static + */ + public static function insertGetId($values, $sequence = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertGetId($values, $sequence); + } + + /** + * Insert new records into the table using a subquery. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return int + * @static + */ + public static function insertUsing($columns, $query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertUsing($columns, $query); + } + + /** + * Insert new records into the table using a subquery while ignoring errors. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return int + * @static + */ + public static function insertOrIgnoreUsing($columns, $query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertOrIgnoreUsing($columns, $query); + } + + /** + * Update records in a PostgreSQL database using the update from syntax. + * + * @return int + * @static + */ + public static function updateFrom($values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->updateFrom($values); + } + + /** + * Insert or update a record matching the attributes, and fill it with values. + * + * @return bool + * @static + */ + public static function updateOrInsert($attributes, $values = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->updateOrInsert($attributes, $values); + } + + /** + * Increment the given column's values by the given amounts. + * + * @param array $columns + * @param array $extra + * @return int + * @throws \InvalidArgumentException + * @static + */ + public static function incrementEach($columns, $extra = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->incrementEach($columns, $extra); + } + + /** + * Decrement the given column's values by the given amounts. + * + * @param array $columns + * @param array $extra + * @return int + * @throws \InvalidArgumentException + * @static + */ + public static function decrementEach($columns, $extra = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->decrementEach($columns, $extra); + } + + /** + * Run a truncate statement on the table. + * + * @return void + * @static + */ + public static function truncate() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + $instance->truncate(); + } + + /** + * Get all of the query builder's columns in a text-only array with all expressions evaluated. + * + * @return array + * @static + */ + public static function getColumns() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getColumns(); + } + + /** + * Create a raw database expression. + * + * @param mixed $value + * @return \Illuminate\Contracts\Database\Query\Expression + * @static + */ + public static function raw($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->raw($value); + } + + /** + * Get the current query value bindings in a flattened array. + * + * @return array + * @static + */ + public static function getBindings() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getBindings(); + } + + /** + * Get the raw array of bindings. + * + * @return array + * @static + */ + public static function getRawBindings() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getRawBindings(); + } + + /** + * Set the bindings on the query builder. + * + * @param string $type + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function setBindings($bindings, $type = 'where') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->setBindings($bindings, $type); + } + + /** + * Add a binding to the query. + * + * @param mixed $value + * @param string $type + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function addBinding($value, $type = 'where') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addBinding($value, $type); + } + + /** + * Cast the given binding value. + * + * @param mixed $value + * @return mixed + * @static + */ + public static function castBinding($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->castBinding($value); + } + + /** + * Merge an array of bindings into our bindings. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function mergeBindings($query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->mergeBindings($query); + } + + /** + * Remove all of the expressions from a list of bindings. + * + * @return array + * @static + */ + public static function cleanBindings($bindings) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->cleanBindings($bindings); + } + + /** + * Get the database query processor instance. + * + * @return \Illuminate\Database\Query\Processors\Processor + * @static + */ + public static function getProcessor() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getProcessor(); + } + + /** + * Get the query grammar instance. + * + * @return \Illuminate\Database\Query\Grammars\Grammar + * @static + */ + public static function getGrammar() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getGrammar(); + } + + /** + * Use the "write" PDO connection when executing the query. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function useWritePdo() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->useWritePdo(); + } + + /** + * Clone the query without the given properties. + * + * @return static + * @static + */ + public static function cloneWithout($properties) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->cloneWithout($properties); + } + + /** + * Clone the query without the given bindings. + * + * @return static + * @static + */ + public static function cloneWithoutBindings($except) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->cloneWithoutBindings($except); + } + + /** + * Dump the current SQL and bindings. + * + * @param mixed $args + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function dump(...$args) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dump(...$args); + } + + /** + * Dump the raw current SQL with embedded bindings. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function dumpRawSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dumpRawSql(); + } + + /** + * Die and dump the current SQL and bindings. + * + * @return never + * @static + */ + public static function dd() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dd(); + } + + /** + * Die and dump the current SQL with embedded bindings. + * + * @return never + * @static + */ + public static function ddRawSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->ddRawSql(); + } + + /** + * Add a where clause to determine if a "date" column is in the past to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function wherePast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->wherePast($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the past or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNowOrPast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNowOrPast($columns); + } + + /** + * Add an "or where" clause to determine if a "date" column is in the past to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWherePast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWherePast($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the past or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNowOrPast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNowOrPast($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the future to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereFuture($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the future or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNowOrFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNowOrFuture($columns); + } + + /** + * Add an "or where" clause to determine if a "date" column is in the future to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereFuture($columns); + } + + /** + * Add an "or where" clause to determine if a "date" column is in the future or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNowOrFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNowOrFuture($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is today to the query. + * + * @param array|string $columns + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereToday($columns, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereToday($columns, $boolean); + } + + /** + * Add a "where date" clause to determine if a "date" column is before today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereBeforeToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereBeforeToday($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is today or before to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereTodayOrBefore($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereTodayOrBefore($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is after today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereAfterToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereAfterToday($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is today or after to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereTodayOrAfter($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereTodayOrAfter($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is today to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereToday($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is before today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereBeforeToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereBeforeToday($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is today or before to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereTodayOrBefore($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereTodayOrBefore($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is after today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereAfterToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereAfterToday($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is today or after to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereTodayOrAfter($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereTodayOrAfter($columns); + } + + /** + * Explains the query. + * + * @return \Illuminate\Support\Collection + * @static + */ + public static function explain() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->explain(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Database\Query\Builder::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Database\Query\Builder::mixin($mixin, $replace); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Database\Query\Builder::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->macroCall($method, $parameters); + } + +} + class Event extends \Illuminate\Support\Facades\Event {} + class File extends \Illuminate\Support\Facades\File {} + class Gate extends \Illuminate\Support\Facades\Gate {} + class Hash extends \Illuminate\Support\Facades\Hash {} + class Http extends \Illuminate\Support\Facades\Http {} + class Js extends \Illuminate\Support\Js {} + class Lang extends \Illuminate\Support\Facades\Lang {} + class Log extends \Illuminate\Support\Facades\Log {} + class Mail extends \Illuminate\Support\Facades\Mail {} + class Notification extends \Illuminate\Support\Facades\Notification {} + class Number extends \Illuminate\Support\Number {} + class Password extends \Illuminate\Support\Facades\Password {} + class Process extends \Illuminate\Support\Facades\Process {} + class Queue extends \Illuminate\Support\Facades\Queue {} + class RateLimiter extends \Illuminate\Support\Facades\RateLimiter {} + class Redirect extends \Illuminate\Support\Facades\Redirect {} + class Request extends \Illuminate\Support\Facades\Request {} + class Response extends \Illuminate\Support\Facades\Response {} + class Route extends \Illuminate\Support\Facades\Route {} + class Schedule extends \Illuminate\Support\Facades\Schedule {} + class Schema extends \Illuminate\Support\Facades\Schema {} + class Session extends \Illuminate\Support\Facades\Session {} + class Storage extends \Illuminate\Support\Facades\Storage {} + class Str extends \Illuminate\Support\Str {} + class URL extends \Illuminate\Support\Facades\URL {} + class Uri extends \Illuminate\Support\Uri {} + class Validator extends \Illuminate\Support\Facades\Validator {} + class View extends \Illuminate\Support\Facades\View {} + class Vite extends \Illuminate\Support\Facades\Vite {} +} + + + + + diff --git a/TA_API/_ide_helper_models.php b/TA_API/_ide_helper_models.php new file mode 100644 index 0000000..c072f8b --- /dev/null +++ b/TA_API/_ide_helper_models.php @@ -0,0 +1,396 @@ + + */ + + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $user_id + * @property string $bank_name + * @property string $account_number + * @property string $account_holder_name + * @property string $status + * @property string|null $rejection_reason + * @property \Illuminate\Support\Carbon|null $verified_at + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\User $user + * @property-read \Illuminate\Database\Eloquent\Collection $withdrawals + * @property-read int|null $withdrawals_count + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount query() + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereAccountHolderName($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereAccountNumber($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereBankName($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereRejectionReason($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereUserId($value) + * @method static \Illuminate\Database\Eloquent\Builder|BankAccount whereVerifiedAt($value) + */ + class BankAccount extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property string|null $transaction_code + * @property int $customer_id + * @property int $tailor_id + * @property \Illuminate\Support\Carbon $appointment_date + * @property \Illuminate\Support\Carbon $appointment_time + * @property string $service_type + * @property string $category + * @property string|null $design_photo + * @property string|null $notes + * @property string $status + * @property numeric|null $total_price + * @property string $payment_status + * @property \Illuminate\Support\Carbon|null $completion_date + * @property array|null $measurements + * @property array|null $repair_details + * @property string|null $repair_photo + * @property string|null $repair_notes + * @property string|null $completion_photo + * @property string|null $completion_notes + * @property \Illuminate\Support\Carbon|null $accepted_at + * @property \Illuminate\Support\Carbon|null $rejected_at + * @property \Illuminate\Support\Carbon|null $completed_at + * @property \Illuminate\Support\Carbon|null $pickup_date + * @property string|null $rejection_reason + * @property string|null $payment_method + * @property string|null $midtrans_snap_token + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\User $customer + * @property-read \Illuminate\Database\Eloquent\Collection $ratings + * @property-read int|null $ratings_count + * @property-read \App\Models\User $tailor + * @method static \Illuminate\Database\Eloquent\Builder|Booking newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Booking newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Booking query() + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereAcceptedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereAppointmentDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereAppointmentTime($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCategory($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletionDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletionNotes($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletionPhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCustomerId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereDesignPhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereMeasurements($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereMidtransSnapToken($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereNotes($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking wherePaymentMethod($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking wherePaymentStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking wherePickupDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRejectedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRejectionReason($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRepairDetails($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRepairNotes($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRepairPhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereServiceType($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereTailorId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereTotalPrice($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereTransactionCode($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereUpdatedAt($value) + */ + class Booking extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $user_id + * @property string $photo + * @property string|null $title + * @property string|null $description + * @property string|null $category + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\User $tailor + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery query() + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereCategory($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery wherePhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereTitle($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereUserId($value) + */ + class TailorGallery extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $booking_id + * @property int $customer_id + * @property int $tailor_id + * @property numeric $rating + * @property string|null $review + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\Booking $booking + * @property-read \App\Models\User $customer + * @property-read \App\Models\User $tailor + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating query() + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereBookingId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereCustomerId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereRating($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereReview($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereTailorId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereUpdatedAt($value) + */ + class TailorRating extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $user_id + * @property string $name + * @property string $description + * @property numeric $price + * @property string $category + * @property int $estimated_days + * @property bool $is_available + * @property string|null $service_photo + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\User $tailor + * @method static \Illuminate\Database\Eloquent\Builder|TailorService newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorService newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorService query() + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereCategory($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereEstimatedDays($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereIsAvailable($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService wherePrice($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereServicePhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorService whereUserId($value) + */ + class TailorService extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property string $name + * @property string $category + * @property string|null $icon + * @property string|null $photo + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $tailors + * @property-read int|null $tailors_count + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization query() + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization whereCategory($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization whereIcon($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization wherePhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorSpecialization whereUpdatedAt($value) + */ + class TailorSpecialization extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property string $name + * @property string $email + * @property string $password + * @property string $role + * @property string|null $phone_number + * @property string|null $address + * @property float|null $latitude + * @property float|null $longitude + * @property string|null $shop_description + * @property string|null $profile_photo + * @property \Illuminate\Support\Carbon|null $email_verified_at + * @property string|null $remember_token + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $bankAccounts + * @property-read int|null $bank_accounts_count + * @property-read \Illuminate\Database\Eloquent\Collection $bookings + * @property-read int|null $bookings_count + * @property-read \Illuminate\Database\Eloquent\Collection $customerBookings + * @property-read int|null $customer_bookings_count + * @property-read \Illuminate\Database\Eloquent\Collection $gallery + * @property-read int|null $gallery_count + * @property-read \Illuminate\Database\Eloquent\Collection $givenRatings + * @property-read int|null $given_ratings_count + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read int|null $notifications_count + * @property-read \Illuminate\Database\Eloquent\Collection $preferredSpecializations + * @property-read int|null $preferred_specializations_count + * @property-read \Illuminate\Database\Eloquent\Collection $ratings + * @property-read int|null $ratings_count + * @property-read \Illuminate\Database\Eloquent\Collection $services + * @property-read int|null $services_count + * @property-read \Illuminate\Database\Eloquent\Collection $specializations + * @property-read int|null $specializations_count + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read int|null $tokens_count + * @property-read \App\Models\Wallet|null $wallet + * @method static \Database\Factories\UserFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|User newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|User query() + * @method static \Illuminate\Database\Eloquent\Builder|User whereAddress($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereEmail($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereEmailVerifiedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereLatitude($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereLongitude($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|User wherePassword($value) + * @method static \Illuminate\Database\Eloquent\Builder|User wherePhoneNumber($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereProfilePhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereRememberToken($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereRole($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereShopDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value) + */ + class User extends \Eloquent implements \Illuminate\Contracts\Auth\MustVerifyEmail {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $user_id + * @property float $balance + * @property string $status + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $transactions + * @property-read int|null $transactions_count + * @property-read \App\Models\User $user + * @property-read \Illuminate\Database\Eloquent\Collection $withdrawals + * @property-read int|null $withdrawals_count + * @method static \Illuminate\Database\Eloquent\Builder|Wallet newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Wallet newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Wallet query() + * @method static \Illuminate\Database\Eloquent\Builder|Wallet whereBalance($value) + * @method static \Illuminate\Database\Eloquent\Builder|Wallet whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Wallet whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Wallet whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Wallet whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Wallet whereUserId($value) + */ + class Wallet extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $wallet_id + * @property int|null $booking_id + * @property string $type + * @property float $amount + * @property string $description + * @property string $status + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\Booking|null $booking + * @property-read \App\Models\Wallet $wallet + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction query() + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereAmount($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereBookingId($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereType($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|WalletTransaction whereWalletId($value) + */ + class WalletTransaction extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $wallet_id + * @property int $bank_account_id + * @property float $amount + * @property string $status + * @property string|null $rejection_reason + * @property string|null $proof_of_payment + * @property \Illuminate\Support\Carbon|null $processed_at + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\BankAccount $bankAccount + * @property-read \App\Models\Wallet $wallet + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal query() + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereAmount($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereBankAccountId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereProcessedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereProofOfPayment($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereRejectionReason($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Withdrawal whereWalletId($value) + */ + class Withdrawal extends \Eloquent {} +} + diff --git a/TA_API/app/Http/Controllers/Api/AdminDashboardController.php b/TA_API/app/Http/Controllers/Api/AdminDashboardController.php new file mode 100644 index 0000000..dbbac06 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/AdminDashboardController.php @@ -0,0 +1,115 @@ +count(); + $totalPelanggan = User::where('role', 'pelanggan')->count(); + $totalBookings = Booking::count(); + $totalServices = TailorService::count(); + + // Get average rating for all tailors + $averageRating = TailorRating::avg('rating') ?? 0; + + // Get bookings statistics + $bookingStats = Booking::select('status', DB::raw('count(*) as total')) + ->groupBy('status') + ->get() + ->pluck('total', 'status') + ->toArray(); + + // Get recent bookings + $recentBookings = Booking::with(['customer:id,name', 'tailor:id,name']) + ->latest() + ->take(5) + ->get() + ->map(function ($booking) { + return [ + 'id' => $booking->id, + 'customer_name' => $booking->customer->name, + 'tailor_name' => $booking->tailor->name, + 'status' => $booking->status, + 'created_at' => $booking->created_at + ]; + }); + + // Get monthly booking statistics for the last 6 months + $monthlyStats = Booking::select( + DB::raw('DATE_FORMAT(created_at, "%Y-%m") as month'), + DB::raw('count(*) as total_bookings'), + DB::raw('SUM(CASE WHEN status = "completed" THEN 1 ELSE 0 END) as completed_bookings') + ) + ->where('created_at', '>=', Carbon::now()->subMonths(6)) + ->groupBy('month') + ->orderBy('month') + ->get(); + + // Get top rated tailors + $topTailors = User::where('role', 'penjahit') + ->withAvg('ratings as average_rating', 'rating') + ->withCount('ratings') + ->withCount('bookings') + ->having('ratings_count', '>', 0) + ->orderByDesc('average_rating') + ->take(5) + ->get() + ->map(function ($tailor) { + return [ + 'id' => $tailor->id, + 'name' => $tailor->name, + 'average_rating' => round($tailor->average_rating, 1), + 'total_ratings' => $tailor->ratings_count, + 'total_bookings' => $tailor->bookings_count + ]; + }); + + // Get latest registered users (both tailors and customers) + $recentUsers = User::whereIn('role', ['penjahit', 'pelanggan']) + ->latest() + ->take(5) + ->select('id', 'name', 'role', 'created_at') + ->get(); + + return response()->json([ + 'status' => 'success', + 'data' => [ + 'summary' => [ + 'total_penjahit' => $totalPenjahit, + 'total_pelanggan' => $totalPelanggan, + 'total_bookings' => $totalBookings, + 'total_services' => $totalServices, + 'average_rating' => round($averageRating, 1) + ], + 'booking_statistics' => [ + 'by_status' => $bookingStats, + 'monthly' => $monthlyStats + ], + 'recent_bookings' => $recentBookings, + 'top_tailors' => $topTailors, + 'recent_users' => $recentUsers + ] + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Failed to retrieve dashboard data', + 'error' => $e->getMessage() + ], 500); + } + } +} \ No newline at end of file diff --git a/TA_API/app/Http/Controllers/Api/AdminWithdrawalController.php b/TA_API/app/Http/Controllers/Api/AdminWithdrawalController.php new file mode 100644 index 0000000..5b11e47 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/AdminWithdrawalController.php @@ -0,0 +1,220 @@ +where('status', 'pending') + ->latest() + ->get(); + + return $this->sendResponse($withdrawals, 'Pending withdrawals retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function getPendingBankAccounts() + { + try { + $pendingBankAccounts = BankAccount::with('user') + ->where('status', 'pending') + ->latest() + ->get(); + + return $this->sendResponse($pendingBankAccounts, 'Pending bank accounts retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function processWithdrawal(Request $request, Withdrawal $withdrawal) + { + try { + $validator = Validator::make($request->all(), [ + 'status' => 'required|in:completed,rejected', + 'rejection_reason' => 'required_if:status,rejected|string|nullable', + 'proof_of_payment' => 'required_if:status,completed|file|image|max:2048' + ]); + + if ($validator->fails()) { + return $this->sendError('Validation Error.', $validator->errors(), 422); + } + + // Pastikan status masih pending + if ($withdrawal->status !== 'pending') { + return $this->sendError('Error.', ['status' => ['Withdrawal sudah diproses sebelumnya']], 422); + } + + if ($request->status === 'rejected') { + // Kembalikan saldo ke wallet + $withdrawal->wallet->addBalance( + $withdrawal->amount, + 'Refund for rejected withdrawal #' . $withdrawal->id + ); + + $withdrawal->update([ + 'status' => 'rejected', + 'rejection_reason' => $request->rejection_reason, + 'processed_at' => now() + ]); + + return $this->sendResponse($withdrawal, 'Withdrawal rejected successfully'); + } else { + // Status completed + if ($request->hasFile('proof_of_payment')) { + $path = $request->file('proof_of_payment')->store('proof_of_payments', 'public'); + + $withdrawal->update([ + 'status' => 'completed', + 'rejection_reason' => null, + 'proof_of_payment' => $path, + 'processed_at' => now() + ]); + + return $this->sendResponse($withdrawal, 'Withdrawal completed successfully'); + } + } + + return $this->sendError('Error.', ['proof_of_payment' => ['Bukti pembayaran wajib diupload untuk status completed']], 422); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function verifyBankAccount(Request $request, BankAccount $bankAccount) + { + try { + $validator = Validator::make($request->all(), [ + 'status' => 'required|in:active,rejected', + 'rejection_reason' => 'required_if:status,rejected|string|nullable' + ]); + + if ($validator->fails()) { + return $this->sendError('Validation Error.', $validator->errors(), 422); + } + + $data = [ + 'status' => $request->status, + 'verified_at' => now() + ]; + + // Hanya tambahkan rejection_reason jika status rejected + if ($request->status === 'rejected') { + $data['rejection_reason'] = $request->rejection_reason; + } else { + $data['rejection_reason'] = null; // Set null ketika status active + } + + $bankAccount->update($data); + + return $this->sendResponse($bankAccount, 'Bank account verification completed'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function getVerifiedBankAccounts(Request $request) + { + try { + $query = BankAccount::with('user') + ->whereIn('status', ['active', 'rejected']) + ->where('verified_at', '!=', null); + + // Filter berdasarkan status jika parameter status disediakan + if ($request->has('status') && in_array($request->status, ['active', 'rejected'])) { + $query->where('status', $request->status); + } + + // Filter berdasarkan pencarian nama pengguna atau nomor rekening + if ($request->has('search')) { + $search = $request->search; + $query->whereHas('user', function($q) use ($search) { + $q->where('name', 'like', "%{$search}%"); + })->orWhere('account_number', 'like', "%{$search}%") + ->orWhere('account_holder_name', 'like', "%{$search}%") + ->orWhere('bank_name', 'like', "%{$search}%"); + } + + $verifiedBankAccounts = $query->latest('verified_at')->get(); + + return $this->sendResponse($verifiedBankAccounts, 'Verified bank accounts retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function getWithdrawalHistory(Request $request) + { + try { + $query = Withdrawal::with(['wallet.user', 'bankAccount']) + ->whereIn('status', ['completed', 'rejected']); + + // Filter berdasarkan status + if ($request->has('status') && in_array($request->status, ['completed', 'rejected'])) { + $query->where('status', $request->status); + } + + // Filter berdasarkan pencarian nama pengguna, nomor rekening atau bank + if ($request->has('search')) { + $search = $request->search; + $query->whereHas('wallet.user', function($q) use ($search) { + $q->where('name', 'like', "%{$search}%"); + })->orWhereHas('bankAccount', function($q) use ($search) { + $q->where('account_number', 'like', "%{$search}%") + ->orWhere('account_holder_name', 'like', "%{$search}%") + ->orWhere('bank_name', 'like', "%{$search}%"); + }); + } + + // Filter berdasarkan periode tanggal + if ($request->has('from_date')) { + $query->whereDate('created_at', '>=', $request->from_date); + } + + if ($request->has('to_date')) { + $query->whereDate('created_at', '<=', $request->to_date); + } + + // Pengurutan + $sortBy = $request->get('sort_by', 'processed_at'); + $sortOrder = $request->get('sort_order', 'desc'); + + if (in_array($sortBy, ['created_at', 'amount', 'processed_at'])) { + $query->orderBy($sortBy, $sortOrder); + } + + // Paginasi hasil + $perPage = $request->get('per_page', 15); + $withdrawals = $query->paginate($perPage); + + return $this->sendResponse($withdrawals, 'Withdrawal history retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function getBankAccountDetail(BankAccount $bankAccount) + { + try { + // Load user dan riwayat withdrawal + $bankAccount->load(['user', 'withdrawals']); + + return $this->sendResponse($bankAccount, 'Bank account detail retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/AuthController.php b/TA_API/app/Http/Controllers/Api/AuthController.php new file mode 100644 index 0000000..a594077 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/AuthController.php @@ -0,0 +1,479 @@ +groupBy('category') + ->map(function ($items) { + return $items->map(function ($item) { + return [ + 'id' => $item->id, + 'name' => $item->name, + 'photo' => $item->photo, + 'category' => $item->category + ]; + }); + }); + + return $specializations; + } + + /** + * Register pelanggan + */ + public function registerPelanggan(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users', + 'password' => 'required|string|min:8', + 'phone_number' => 'required|string|max:15', + 'address' => 'required|string|max:500', + 'preferred_specializations' => 'nullable|array', + 'preferred_specializations.*' => 'exists:tailor_specializations,id', + 'latitude' => 'required|numeric|between:-90,90', + 'longitude' => 'required|numeric|between:-180,180' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + $user = User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + 'role' => 'pelanggan', + 'phone_number' => $request->phone_number, + 'address' => $request->address, + 'latitude' => $request->latitude, + 'longitude' => $request->longitude + ]); + + if ($request->has('preferred_specializations') && !empty($request->preferred_specializations)) { + $user->preferredSpecializations()->attach($request->preferred_specializations); + } + + // Send verification email + $user->sendEmailVerificationNotification(); + + $token = $user->createToken('auth_token', ['pelanggan'])->plainTextToken; + + // Get all specializations with photos + $specializations = $this->getSpecializationData(); + + return $this->sendResponse([ + 'user' => $user, + 'access_token' => $token, + 'token_type' => 'Bearer', + 'specializations' => $specializations, + 'selected_specializations' => $user->preferredSpecializations + ], 'Registrasi pelanggan berhasil. Silakan cek email Anda untuk verifikasi.'); + + } catch (\Exception $e) { + return $this->sendError('Error registrasi.', ['error' => $e->getMessage()], 500); + } + } + + /** + * Register penjahit + */ + public function registerPenjahit(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users', + 'password' => 'required|string|min:8', + 'phone_number' => 'required|string|max:15', + 'address' => 'required|string|max:500', + 'shop_description' => 'required|string|max:1000', + 'specializations' => 'required|array|min:1', + 'specializations.*' => 'exists:tailor_specializations,id', + 'latitude' => 'required|numeric|between:-90,90', + 'longitude' => 'required|numeric|between:-180,180' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + $user = User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + 'role' => 'penjahit', + 'phone_number' => $request->phone_number, + 'address' => $request->address, + 'latitude' => $request->latitude, + 'longitude' => $request->longitude, + 'shop_description' => $request->shop_description + ]); + + // Attach specializations + $user->specializations()->attach($request->specializations); + + // Send verification email + $user->sendEmailVerificationNotification(); + + $token = $user->createToken('auth_token', ['penjahit'])->plainTextToken; + + return $this->sendResponse([ + 'user' => $user, + 'access_token' => $token, + 'token_type' => 'Bearer' + ], 'Registrasi penjahit berhasil. Silakan cek email Anda untuk verifikasi.'); + + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat registrasi'], 500); + } + } + + /** + * Login pelanggan + */ + public function loginPelanggan(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'email' => 'required|email', + 'password' => 'required' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + if (!Auth::attempt($request->only('email', 'password'))) { + return $this->sendError('Unauthorized.', ['error' => 'Email atau password salah'], 401); + } + + $user = Auth::user(); + + // Check if user is pelanggan + if (!$user->isPelanggan()) { + Auth::logout(); + return $this->sendError('Unauthorized.', ['error' => 'Akun ini bukan akun pelanggan'], 401); + } + + // Check if email is verified + if (!$user->hasVerifiedEmail()) { + // Resend verification email + $user->sendEmailVerificationNotification(); + Auth::logout(); + return $this->sendError('Unauthorized.', [ + 'error' => 'Email belum diverifikasi. Kami telah mengirim ulang email verifikasi ke ' . $user->email + ], 401); + } + + $token = $user->createToken('auth_token', ['pelanggan'])->plainTextToken; + + // Get all specializations with photos + $specializations = $this->getSpecializationData(); + + return $this->sendResponse([ + 'user' => $user, + 'access_token' => $token, + 'token_type' => 'Bearer', + 'specializations' => $specializations, + 'selected_specializations' => $user->preferredSpecializations + ], 'Login pelanggan berhasil.'); + + } catch (\Exception $e) { + return $this->sendError('Error login.', ['error' => $e->getMessage()], 500); + } + } + + /** + * Login penjahit + */ + public function loginPenjahit(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'email' => 'required|email', + 'password' => 'required|string' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + if (!Auth::attempt($request->only('email', 'password'))) { + return $this->sendError('Unauthorized.', ['error' => 'Email atau password salah'], 401); + } + + $user = User::where('email', $request->email)->firstOrFail(); + + if ($user->role !== 'penjahit') { + return $this->sendError('Unauthorized.', ['error' => 'Akun ini bukan akun penjahit'], 401); + } + + // Check if email is verified + if (!$user->hasVerifiedEmail()) { + // Resend verification email + $user->sendEmailVerificationNotification(); + Auth::logout(); + return $this->sendError('Unauthorized.', [ + 'error' => 'Email belum diverifikasi. Kami telah mengirim ulang email verifikasi ke ' . $user->email + ], 401); + } + + $token = $user->createToken('auth_token', ['penjahit'])->plainTextToken; + + return $this->sendResponse([ + 'user' => $user, + 'access_token' => $token, + 'token_type' => 'Bearer' + ], 'Login penjahit berhasil'); + + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat login'], 500); + } + } + + /** + * Login admin + */ + public function loginAdmin(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'email' => 'required|email', + 'password' => 'required' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + if (!Auth::attempt($request->only('email', 'password'))) { + return $this->sendError('Unauthorized.', ['error' => 'Email atau password salah'], 401); + } + + $user = Auth::user(); + if (!$user->isAdmin()) { + Auth::logout(); + return $this->sendError('Unauthorized.', ['error' => 'Akun ini bukan akun admin'], 401); + } + + $token = $user->createToken('auth_token', ['admin'])->plainTextToken; + + return $this->sendResponse([ + 'user' => $user, + 'access_token' => $token, + 'token_type' => 'Bearer' + ], 'Login admin berhasil.'); + + } catch (\Exception $e) { + return $this->sendError('Error login.', ['error' => $e->getMessage()], 500); + } + } + + /** + * Logout user + */ + public function logout() + { + try { + auth()->user()->tokens()->delete(); + return $this->sendResponse([], 'Logout berhasil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat logout'], 500); + } + } + + /** + * Get user profile + */ + public function profile() + { + try { + $user = Auth::user(); + if ($user->role === 'penjahit') { + $user->load('specializations'); + } + return $this->sendResponse($user, 'Data profil berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil profil'], 500); + } + } + + /** + * Get all specializations + */ + public function getSpecializations() + { + try { + $specializations = \App\Models\TailorSpecialization::all(); + return $this->sendResponse($specializations, 'Data spesialisasi berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data spesialisasi'], 500); + } + } + + /** + * Upload foto profil + */ + public function uploadProfilePhoto(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'profile_photo' => 'required|image|mimes:jpeg,png,jpg|max:2048' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + $user = Auth::user(); + + // Hapus foto profil lama jika ada + if ($user->profile_photo) { + $oldPhotoPath = str_replace('/storage/', '', $user->profile_photo); + if (Storage::disk('public')->exists($oldPhotoPath)) { + Storage::disk('public')->delete($oldPhotoPath); + } + } + + // Upload dan simpan foto baru + $photo = $request->file('profile_photo'); + $fileName = time() . '_' . $user->id . '.' . $photo->getClientOriginalExtension(); + $photo->storeAs('profile_photos', $fileName, 'public'); + + // Update path foto di database + $user->profile_photo = '/storage/profile_photos/' . $fileName; + $user->save(); + + return $this->sendResponse([ + 'profile_photo' => $user->profile_photo + ], 'Foto profil berhasil diupload.'); + + } catch (\Exception $e) { + return $this->sendError('Error upload foto.', ['error' => $e->getMessage()], 500); + } + } + + /** + * Update user profile + */ + public function updateProfile(Request $request) + { + try { + $user = Auth::user(); + + // Different validation rules based on user role + $validationRules = [ + 'name' => 'string|max:255', + 'phone_number' => 'string|max:15', + 'address' => 'string|max:500', + 'current_password' => 'string', + 'new_password' => 'string|min:8|confirmed', + ]; + + // Add penjahit specific validation rules + if ($user->isPenjahit()) { + $validationRules['shop_description'] = 'string|max:1000'; + $validationRules['specializations'] = 'array'; + $validationRules['specializations.*'] = 'exists:tailor_specializations,id'; + } + + // Add pelanggan specific validation rules + if ($user->isPelanggan()) { + $validationRules['preferred_specializations'] = 'array'; + $validationRules['preferred_specializations.*'] = 'exists:tailor_specializations,id'; + $validationRules['latitude'] = 'numeric|between:-90,90'; + $validationRules['longitude'] = 'numeric|between:-180,180'; + } + + $validator = Validator::make($request->all(), $validationRules); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Check if password update is requested + if ($request->has('current_password') && $request->has('new_password')) { + // Verify current password + if (!Hash::check($request->current_password, $user->password)) { + return $this->sendError('Error validasi.', ['current_password' => 'Password saat ini tidak sesuai'], 422); + } + + // Update to new password + $user->password = Hash::make($request->new_password); + } + + // Update basic profile fields + if ($request->has('name')) { + $user->name = $request->name; + } + + if ($request->has('phone_number')) { + $user->phone_number = $request->phone_number; + } + + if ($request->has('address')) { + $user->address = $request->address; + } + + // Update penjahit specific fields + if ($user->isPenjahit()) { + if ($request->has('shop_description')) { + $user->shop_description = $request->shop_description; + } + + // Update specializations if provided + if ($request->has('specializations')) { + $user->specializations()->sync($request->specializations); + } + } + + // Update pelanggan specific fields + if ($user->isPelanggan()) { + if ($request->has('latitude')) { + $user->latitude = $request->latitude; + } + + if ($request->has('longitude')) { + $user->longitude = $request->longitude; + } + + // Update preferred specializations if provided + if ($request->has('preferred_specializations')) { + $user->preferredSpecializations()->sync($request->preferred_specializations); + } + } + + $user->save(); + + // Load relationships based on user role + if ($user->isPenjahit()) { + $user->load('specializations'); + } elseif ($user->isPelanggan()) { + $user->load('preferredSpecializations'); + } + + return $this->sendResponse($user, 'Profil berhasil diperbarui'); + + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memperbarui profil: ' . $e->getMessage()], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/BaseController.php b/TA_API/app/Http/Controllers/Api/BaseController.php new file mode 100644 index 0000000..d5a1385 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/BaseController.php @@ -0,0 +1,49 @@ + true, + 'data' => $result, + 'message' => $message, + ]; + + return response()->json($response, $code); + } + + /** + * Error response method. + * + * @param string $error + * @param array $errorMessages + * @param int $code + * @return \Illuminate\Http\Response + */ + public function sendError($error, $errorMessages = [], $code = 404) + { + $response = [ + 'success' => false, + 'message' => $error, + ]; + + if (!empty($errorMessages)) { + $response['data'] = $errorMessages; + } + + return response()->json($response, $code); + } +} diff --git a/TA_API/app/Http/Controllers/Api/BookingController.php b/TA_API/app/Http/Controllers/Api/BookingController.php new file mode 100644 index 0000000..73dc4ed --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/BookingController.php @@ -0,0 +1,1091 @@ +all(), [ + 'tailor_id' => 'required|exists:users,id', + 'appointment_date' => 'required|date|after_or_equal:today', + 'appointment_time' => 'required|date_format:H:i', + 'service_type' => 'required|in:Perbaikan,Jahit Baru', + 'category' => 'required|in:Atasan,Bawahan,Terusan', + 'design_photo' => 'required|image|max:2048', // max 2MB + 'notes' => 'nullable|string', + 'payment_method' => 'required|string|max:50' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + try { + // Check if tailor exists and is actually a tailor + $tailor = User::findOrFail($request->tailor_id); + if (!$tailor->isPenjahit()) { + return $this->sendError('Error validasi.', ['tailor_id' => 'ID yang dipilih bukan penjahit'], 422); + } + + // Convert appointment time to Carbon instance + $requestedTime = Carbon::parse($request->appointment_time); + $requestedDate = Carbon::parse($request->appointment_date); + + // Calculate time slot (2 hours) + $slotStart = $requestedTime->copy(); + $slotEnd = $requestedTime->copy()->addHours(2); + + // Check if there is any booking that overlaps with this time slot + $existingBooking = Booking::where('tailor_id', $request->tailor_id) + ->where('appointment_date', $request->appointment_date) + ->where('status', '!=', 'dibatalkan') + ->where(function($query) use ($slotStart, $slotEnd) { + $query->where(function($q) use ($slotStart, $slotEnd) { + // Check if existing booking's time slot overlaps with requested slot + $q->where(function($q) use ($slotStart, $slotEnd) { + $q->whereRaw('TIME(appointment_time) BETWEEN ? AND ?', [ + $slotStart->format('H:i:s'), + $slotEnd->format('H:i:s') + ]); + }) + ->orWhere(function($q) use ($slotStart, $slotEnd) { + $q->whereRaw('TIME(DATE_ADD(appointment_time, INTERVAL 2 HOUR)) BETWEEN ? AND ?', [ + $slotStart->format('H:i:s'), + $slotEnd->format('H:i:s') + ]); + }); + }); + }) + ->first(); + + if ($existingBooking) { + return $this->sendError('Error validasi.', [ + 'appointment' => 'Jadwal tidak tersedia. Penjahit sudah memiliki booking pada waktu tersebut (durasi 2 jam)' + ], 422); + } + + $booking = new Booking($request->all()); + $booking->customer_id = Auth::id(); + $booking->status = 'reservasi'; + $booking->payment_status = 'unpaid'; + $booking->payment_method = $request->payment_method; + + // Generate transaction code + $booking->transaction_code = $this->generateTransactionCode(); + + // Handle design photo upload + if ($request->hasFile('design_photo')) { + $path = $request->file('design_photo')->store('design_photos', 'public'); + $booking->design_photo = $path; + } + + $booking->save(); + + // Load relationships + $booking->load(['customer', 'tailor']); + + return $this->sendResponse($booking, 'Booking berhasil dibuat.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat membuat booking'], 500); + } + } + + /** + * Get customer's bookings with filter + */ + public function customerBookings(Request $request) + { + try { + $query = Booking::where('customer_id', Auth::id()) + ->with(['tailor', 'ratings']); + + // Filter by status if provided + if ($request->has('status')) { + $query->where('status', $request->status); + } + + $bookings = $query->orderBy('created_at', 'desc')->get(); + + // Transform the bookings to add completion date information + $transformedBookings = $bookings->map(function ($booking) { + $data = $booking->toArray(); + + // Add formatted completed_at date if booking is completed + if ($booking->status === 'selesai' && $booking->completed_at) { + $data['completed_at_formatted'] = Carbon::parse($booking->completed_at)->format('Y-m-d'); + } + + // Add rating information if exists + if ($booking->ratings->count() > 0) { + $rating = $booking->ratings->first(); + $data['rating'] = [ + 'id' => $rating->id, + 'rating' => $rating->rating, + 'review' => $rating->review, + 'created_at' => $rating->created_at, + 'updated_at' => $rating->updated_at + ]; + } else { + $data['rating'] = null; + } + + // Pastikan transaction_code dan payment_method selalu tersedia di respons + $data['transaction_code'] = $booking->transaction_code; + $data['payment_method'] = $booking->payment_method; + + return $data; + }); + + return $this->sendResponse($transformedBookings, 'Data booking berhasil diambil.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data booking'], 500); + } + } + + /** + * Get tailor's bookings with filter + */ + public function tailorBookings(Request $request) + { + try { + $query = Booking::where('tailor_id', Auth::id()) + ->with(['customer', 'ratings']); + + // Filter by status if provided + if ($request->has('status')) { + $query->where('status', $request->status); + } + + $bookings = $query->orderBy('created_at', 'desc')->get(); + + // Transform bookings to include rating information + $transformedBookings = $bookings->map(function ($booking) { + $data = $booking->toArray(); + + // Add rating information if exists + if ($booking->ratings->count() > 0) { + $rating = $booking->ratings->first(); + $data['rating'] = [ + 'id' => $rating->id, + 'rating' => $rating->rating, + 'review' => $rating->review, + 'created_at' => $rating->created_at, + 'updated_at' => $rating->updated_at + ]; + } else { + $data['rating'] = null; + } + + // Pastikan transaction_code dan payment_method selalu tersedia di respons + $data['transaction_code'] = $booking->transaction_code; + $data['payment_method'] = $booking->payment_method; + + return $data; + }); + + return $this->sendResponse($transformedBookings, 'Data booking berhasil diambil.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data booking'], 500); + } + } + + /** + * Update booking status + */ + public function updateStatus(Request $request, Booking $booking) + { + $validator = Validator::make($request->all(), [ + 'status' => 'required|in:diproses,selesai,dibatalkan', + 'total_price' => 'required_if:status,diproses|numeric|min:0', + 'completion_date' => 'required_if:status,diproses|date|after_or_equal:today' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + try { + // Check if the authenticated user is the tailor of this booking + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengubah status booking ini'], 403); + } + + // Validate status transition + if ($request->status === 'diproses' && !$booking->canBeProcessed()) { + return $this->sendError('Error validasi.', ['status' => 'Booking tidak dapat diproses. Pastikan pembayaran sudah dilakukan.'], 422); + } + + if ($request->status === 'selesai' && !$booking->canBeCompleted()) { + return $this->sendError('Error validasi.', ['status' => 'Booking tidak dapat diselesaikan. Status harus diproses terlebih dahulu.'], 422); + } + + $booking->status = $request->status; + if ($request->status === 'diproses') { + $booking->total_price = $request->total_price; + $booking->completion_date = $request->completion_date; + } + $booking->save(); + + return $this->sendResponse($booking, 'Status booking berhasil diupdate.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate status booking'], 500); + } + } + + /** + * Cancel booking (for customer) + */ + public function cancelBooking(Booking $booking) + { + try { + // Check if the authenticated user is the customer of this booking + if ($booking->customer_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk membatalkan booking ini'], 403); + } + + // Check if booking can be cancelled + if (!$booking->canBeCancelled()) { + return $this->sendError('Error validasi.', ['status' => 'Booking tidak dapat dibatalkan karena sudah diproses'], 422); + } + + $booking->status = 'dibatalkan'; + $booking->save(); + + return $this->sendResponse($booking, 'Booking berhasil dibatalkan.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat membatalkan booking'], 500); + } + } + + /** + * Update payment status + */ + public function updatePaymentStatus(Request $request, Booking $booking) + { + $validator = Validator::make($request->all(), [ + 'payment_status' => 'required|in:paid,success' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + try { + // Periksa apakah pengguna yang terautentikasi adalah penjahit dari booking ini + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengubah status pembayaran ini'], 403); + } + + // Periksa apakah status booking valid untuk perubahan status pembayaran + if (!in_array($booking->status, ['reservasi', 'diproses', 'selesai'])) { + return $this->sendError('Invalid status', ['error' => 'Status pembayaran hanya dapat diubah untuk booking yang aktif'], 422); + } + + // Tentukan status pembayaran berdasarkan metode pembayaran + if ($booking->payment_method === 'COD') { + $booking->payment_status = 'success'; + } else { + $booking->payment_status = 'paid'; + } + + $booking->save(); + + // Memberikan informasi lebih detail pada respons + return $this->sendResponse([ + 'booking' => [ + 'id' => $booking->id, + 'customer_name' => $booking->customer->name, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'status' => $booking->status, + 'total_price' => $booking->total_price, + 'appointment_date' => $booking->appointment_date + ] + ], 'Status pembayaran berhasil diubah menjadi ' . $booking->payment_status . ' oleh penjahit.'); + } catch (\Exception $e) { + \Log::error('Error in updatePaymentStatus: ' . $e->getMessage(), [ + 'booking_id' => $booking->id, + 'tailor_id' => Auth::id(), + 'exception' => $e + ]); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate status pembayaran'], 500); + } + } + + /** + * Tailor accepts booking and changes status to "diproses" + */ + public function acceptBooking(Booking $booking) + { + try { + // Check if user is the tailor + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk menerima pesanan ini'], 403); + } + + // Debug: Log current booking status + \Log::info('Current booking status: ' . $booking->status); + + // Check if booking can be processed + if (!in_array($booking->status, ['pending', 'reservasi'])) { + return $this->sendError('Invalid status', ['error' => 'Pesanan tidak dapat diproses. Status saat ini: ' . $booking->status], 422); + } + + // Update booking status to diproses + $booking->status = 'diproses'; + $booking->accepted_at = now(); + $booking->save(); + + // Load customer relationship for response with correct column name + $booking->load(['customer:id,name,email,phone_number']); + + return $this->sendResponse([ + 'booking' => [ + 'id' => $booking->id, + 'customer_name' => $booking->customer->name, + 'customer_phone' => $booking->customer->phone_number, + 'service_type' => $booking->service_type, + 'category' => $booking->category, + 'appointment_date' => Carbon::parse($booking->appointment_date)->format('Y-m-d'), + 'appointment_time' => $booking->appointment_time, + 'design_photo' => $booking->design_photo, + 'notes' => $booking->notes, + 'status' => $booking->status, + 'accepted_at' => Carbon::parse($booking->accepted_at)->format('Y-m-d H:i:s') + ] + ], 'Pesanan berhasil diterima dan diproses'); + + } catch (\Exception $e) { + \Log::error('Error in acceptBooking: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memproses pesanan'], 500); + } + } + + /** + * Reject booking by tailor + */ + public function rejectBooking(Request $request, Booking $booking) + { + try { + // Validate request + $validator = Validator::make($request->all(), [ + 'rejection_reason' => 'required|string|max:255' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Check if the authenticated user is the tailor assigned to this booking + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk menolak booking ini'], 403); + } + + // Check if booking is in reservasi status + if ($booking->status !== 'reservasi') { + return $this->sendError('Error validasi.', ['error' => 'Booking ini tidak dapat ditolak karena status bukan reservasi'], 422); + } + + $booking->update([ + 'status' => 'dibatalkan', + 'rejection_reason' => $request->rejection_reason, + 'rejected_at' => now() + ]); + + // Load the customer relationship + $booking->load('customer'); + + // TODO: Send notification to customer that booking has been rejected + + return $this->sendResponse($booking, 'Booking telah ditolak'); + } catch (\Exception $e) { + // Log error detail untuk keperluan debugging + \Log::error('Error in rejectBooking: ' . $e->getMessage(), [ + 'booking_id' => $booking->id, + 'exception' => $e + ]); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menolak booking'], 500); + } + } + + /** + * Get booking details + */ + public function show(Booking $booking) + { + try { + // Check if user is authorized to view this booking + if ($booking->customer_id !== Auth::id() && $booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses ke pesanan ini'], 403); + } + + // Load relationships + $booking->load(['customer:id,name,phone_number', 'tailor:id,name,profile_photo']); + + $response = [ + 'id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'customer' => [ + 'name' => $booking->customer->name, + 'phone_number' => $booking->customer->phone_number + ], + 'tailor' => [ + 'name' => $booking->tailor->name, + 'profile_photo' => $booking->tailor->profile_photo + ], + 'appointment_date' => Carbon::parse($booking->appointment_date)->format('Y-m-d'), + 'appointment_time' => $booking->appointment_time, + 'service_type' => $booking->service_type, + 'category' => $booking->category, + 'status' => $booking->status, + 'total_price' => $booking->total_price, + 'completion_date' => $booking->completion_date ? Carbon::parse($booking->completion_date)->format('Y-m-d') : null, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'notes' => $booking->notes, + 'measurements' => $booking->measurements, + 'repair_details' => $booking->repair_details, + 'repair_photo' => $booking->repair_photo, + 'repair_notes' => $booking->repair_notes, + 'completion_photo' => $booking->completion_photo, + 'completion_notes' => $booking->completion_notes, + 'pickup_date' => $booking->pickup_date ? Carbon::parse($booking->pickup_date)->format('Y-m-d') : null + ]; + + return $this->sendResponse($response, 'Detail pesanan berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil detail pesanan'], 500); + } + } + + /** + * Update measurements for the booking + */ + public function updateMeasurements(Request $request, Booking $booking) + { + try { + // Check if the authenticated user is the tailor assigned to this booking + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengupdate ukuran pesanan ini'], 403); + } + + // Check if booking is in correct status + if ($booking->status !== 'diproses') { + return $this->sendError('Error validasi.', ['error' => 'Ukuran hanya dapat diinput setelah booking diterima dan dalam status diproses'], 422); + } + + // Validate measurements based on category + $validator = Validator::make($request->all(), [ + 'measurements' => 'required|array', + 'measurements.lingkar_pinggang' => 'required_if:category,Bawahan,Terusan|numeric', + 'measurements.lingkar_pinggul' => 'required_if:category,Bawahan,Terusan|numeric', + 'measurements.lingkar_paha' => 'required_if:category,Bawahan|numeric', + 'measurements.lingkar_lutut' => 'required_if:category,Bawahan|numeric', + 'measurements.panjang_celana' => 'required_if:category,Bawahan|numeric', + 'measurements.lingkar_badan' => 'required_if:category,Atasan,Terusan|numeric', + 'measurements.lingkar_dada' => 'required_if:category,Atasan,Terusan|numeric', + 'measurements.panjang_lengan' => 'required_if:category,Atasan,Terusan|numeric', + 'measurements.lingkar_lengan' => 'required_if:category,Atasan,Terusan|numeric', + 'measurements.lingkar_pergelangan' => 'required_if:category,Atasan,Terusan|numeric', + 'measurements.panjang_baju' => 'required_if:category,Atasan,Terusan|numeric', + 'measurements.lebar_bahu' => 'required_if:category,Atasan,Terusan|numeric', + 'measurements.panjang_rok' => 'required_if:category,Terusan|numeric', + 'measurements.lingkar_pinggang_dress' => 'required_if:category,Terusan|numeric', + 'measurements.lingkar_ketiak' => 'required_if:category,Terusan|numeric', + 'measurements.panjang_dress' => 'required_if:category,Terusan|numeric' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Update measurements + $booking->measurements = $request->measurements; + $booking->save(); + + return $this->sendResponse($booking, 'Ukuran pesanan berhasil diupdate'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate ukuran pesanan'], 500); + } + } + + /** + * Complete booking and change status to "selesai" + */ + public function completeBooking(Request $request, Booking $booking) + { + try { + // Check if user is the tailor + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk menyelesaikan pesanan ini'], 403); + } + + // Check if booking status is diproses + if ($booking->status !== 'diproses') { + return $this->sendError('Invalid status', ['error' => 'Hanya pesanan dengan status diproses yang dapat diselesaikan'], 422); + } + + // Validate request + $validator = Validator::make($request->all(), [ + 'completion_photo' => 'required|image|mimes:jpeg,jpg,png|max:2048', + 'completion_notes' => 'nullable|string|max:500', + 'total_price' => 'nullable|numeric|min:0' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Upload completion photo + if ($request->hasFile('completion_photo')) { + $photo = $request->file('completion_photo'); + + // Buat direktori jika belum ada + $storagePath = storage_path('app/public/completion_photos'); + if (!file_exists($storagePath)) { + mkdir($storagePath, 0755, true); + } + + // Simpan file dengan nama yang unik + $filename = 'completion_' . time() . '_' . $booking->id . '.' . $photo->getClientOriginalExtension(); + $photo->move($storagePath, $filename); + + // Simpan path relatif ke database untuk akses via URL /storage/completion_photos/... + $booking->completion_photo = 'completion_photos/' . $filename; + } + + // Update price if provided + if ($request->has('total_price')) { + $booking->total_price = $request->total_price; + } + + // Update booking + $booking->status = 'selesai'; + $booking->completion_notes = $request->completion_notes; + $booking->completed_at = now(); + $booking->save(); + + // Load relationships + $booking->load(['customer:id,name,phone_number', 'tailor:id,name']); + + // Tambahkan URL lengkap untuk akses gambar + $completionPhotoUrl = $booking->completion_photo ? url('storage/' . $booking->completion_photo) : null; + + return $this->sendResponse([ + 'id' => $booking->id, + 'status' => $booking->status, + 'completion_photo' => $booking->completion_photo, + 'completion_photo_url' => $completionPhotoUrl, + 'completion_notes' => $booking->completion_notes, + 'total_price' => $booking->total_price, + 'completed_at' => Carbon::parse($booking->completed_at)->format('Y-m-d H:i:s'), + 'customer' => [ + 'name' => $booking->customer->name, + 'phone_number' => $booking->customer->phone_number + ], + 'tailor' => [ + 'name' => $booking->tailor->name + ] + ], 'Pesanan berhasil diselesaikan'); + + } catch (\Exception $e) { + \Log::error('Error in completeBooking: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menyelesaikan pesanan'], 500); + } + } + + /** + * Update repair details for the booking + */ + public function updateRepairDetails(Request $request, Booking $booking) + { + try { + // Check if the authenticated user is the tailor assigned to this booking + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengupdate detail perbaikan'], 403); + } + + // Validate repair details + $validator = Validator::make($request->all(), [ + 'repair_details' => 'required|string|max:1000', + 'repair_photo' => 'nullable|image|max:2048', // max 2MB + 'repair_notes' => 'nullable|string|max:1000' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Handle repair photo upload + if ($request->hasFile('repair_photo')) { + $path = $request->file('repair_photo')->store('repair_photos', 'public'); + $booking->repair_photo = $path; + } + + // Update repair details + $booking->repair_details = $request->repair_details; + $booking->repair_notes = $request->repair_notes; + $booking->save(); + + return $this->sendResponse($booking, 'Detail perbaikan berhasil diupdate'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate detail perbaikan'], 500); + } + } + + /** + * Get tailor's bookings by status + */ + public function tailorBookingsByStatus($status) + { + try { + // Validate status + if (!in_array($status, ['pending', 'diterima', 'diproses', 'selesai', 'dibatalkan', 'reservasi'])) { + return $this->sendError('Error validasi.', ['status' => 'Status tidak valid'], 422); + } + + $bookings = Booking::where('tailor_id', Auth::id()) + ->where('status', $status) + ->with(['customer']) + ->orderBy('created_at', 'desc') + ->get(); + + return $this->sendResponse($bookings, 'Data booking ' . $status . ' berhasil diambil.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data booking'], 500); + } + } + + /** + * Simplified booking creation from tailor detail page + */ + public function bookTailor(Request $request, $tailorId) + { + try { + // Set timezone to Asia/Jakarta + date_default_timezone_set('Asia/Jakarta'); + + // Get today's date in Asia/Jakarta timezone + $today = Carbon::now('Asia/Jakarta')->startOfDay(); + + // Validate request + $validator = Validator::make($request->all(), [ + 'appointment_date' => ['required', 'date', function ($attribute, $value, $fail) use ($today) { + $appointmentDate = Carbon::parse($value)->startOfDay(); + if ($appointmentDate->lt($today)) { + $fail('Tanggal booking harus hari ini atau setelah hari ini.'); + } + }], + 'appointment_time' => 'required|date_format:H:i', + 'service_type' => 'required|in:Perbaikan,Jahit Baru', + 'category' => 'required|in:Atasan,Bawahan,Terusan', + 'design_photo' => 'required|image|mimes:jpeg,png,jpg|max:2048', + 'notes' => 'nullable|string', + 'payment_method' => 'required|string|max:50' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Check if tailor exists and is a valid tailor + $tailor = User::where('id', $tailorId) + ->where('role', 'penjahit') + ->first(); + + if (!$tailor) { + return $this->sendError('Not found.', ['error' => 'Penjahit tidak ditemukan'], 404); + } + + // Convert appointment time to Carbon instance + $requestedTime = Carbon::parse($request->appointment_time); + $requestedDate = Carbon::parse($request->appointment_date); + + // Calculate time slot (2 hours) + $slotStart = $requestedTime->copy(); + $slotEnd = $requestedTime->copy()->addHours(2); + + // Check if there is any booking that overlaps with this time slot + $existingBooking = Booking::where('tailor_id', $tailorId) + ->where('appointment_date', $request->appointment_date) + ->where('status', '!=', 'dibatalkan') + ->where(function($query) use ($slotStart, $slotEnd) { + $query->where(function($q) use ($slotStart, $slotEnd) { + // Check if existing booking's time slot overlaps with requested slot + $q->where(function($q) use ($slotStart, $slotEnd) { + $q->whereRaw('TIME(appointment_time) BETWEEN ? AND ?', [ + $slotStart->format('H:i:s'), + $slotEnd->format('H:i:s') + ]); + }) + ->orWhere(function($q) use ($slotStart, $slotEnd) { + $q->whereRaw('TIME(DATE_ADD(appointment_time, INTERVAL 2 HOUR)) BETWEEN ? AND ?', [ + $slotStart->format('H:i:s'), + $slotEnd->format('H:i:s') + ]); + }); + }); + }) + ->first(); + + if ($existingBooking) { + return $this->sendError('Error validasi.', [ + 'appointment' => 'Jadwal tidak tersedia. Penjahit sudah memiliki booking pada waktu tersebut (durasi 2 jam)' + ], 422); + } + + // Create booking + $booking = new Booking(); + $booking->tailor_id = $tailorId; + $booking->customer_id = Auth::id(); + $booking->appointment_date = $request->appointment_date; + $booking->appointment_time = $request->appointment_time; + $booking->service_type = $request->service_type; + $booking->category = $request->category; + $booking->notes = $request->notes; + $booking->status = 'reservasi'; + $booking->payment_status = 'unpaid'; + $booking->payment_method = $request->payment_method; + + // Generate transaction code + $booking->transaction_code = $this->generateTransactionCode(); + + // Handle design photo if provided + if ($request->hasFile('design_photo')) { + $path = $request->file('design_photo')->store('design_photos', 'public'); + $booking->design_photo = $path; + } + + $booking->save(); + + // Load relationships + $booking->load(['customer', 'tailor']); + + return $this->sendResponse([ + 'booking' => $booking, + 'message' => 'Booking berhasil dibuat', + 'next_steps' => [ + 'payment' => 'Silakan lakukan pembayaran untuk mengkonfirmasi booking', + 'cancellation' => 'Anda dapat membatalkan booking sebelum melakukan pembayaran' + ] + ], 'Booking berhasil dibuat'); + + } catch (\Exception $e) { + \Log::error('Error creating booking: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat membuat booking: ' . $e->getMessage()], 500); + } + } + + /** + * Get customer bookings by status + */ + public function customerBookingsByStatus($status) + { + try { + $allowedStatuses = ['reservasi', 'dikonfirmasi', 'diproses', 'selesai', 'dibatalkan']; + + if (!in_array($status, $allowedStatuses)) { + return $this->sendError('Invalid status', ['error' => 'Status tidak valid'], 422); + } + + $bookings = Booking::where('customer_id', Auth::id()) + ->where('status', $status) + ->with(['tailor:id,name,profile_photo', 'ratings']) + ->orderBy('created_at', 'desc') + ->get() + ->map(function ($booking) use ($status) { + $data = [ + 'id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'tailor_name' => $booking->tailor->name, + 'tailor_photo' => $booking->tailor->profile_photo, + 'payment_method' => $booking->payment_method, + 'payment_status' => $booking->payment_status + ]; + + if ($status === 'selesai') { + $data = array_merge($data, [ + 'service_type' => $booking->service_type, + 'category' => $booking->category, + 'appointment_date' => Carbon::parse($booking->appointment_date)->format('Y-m-d'), + 'completed_at' => $booking->completed_at ? Carbon::parse($booking->completed_at)->format('Y-m-d') : null, + 'total_price' => $booking->total_price ?? 0, + 'has_rating' => $booking->ratings->count() > 0, + 'rating_id' => $booking->ratings->first() ? $booking->ratings->first()->id : null + ]); + } else if ($status === 'diproses') { + $data = array_merge($data, [ + 'service_type' => $booking->service_type, + 'appointment_date' => Carbon::parse($booking->appointment_date)->format('Y-m-d'), + 'completed_at' => $booking->completed_at ? Carbon::parse($booking->completed_at)->format('Y-m-d') : null, + 'total_price' => $booking->total_price ?? 0, + 'design_photo' => $booking->design_photo ? '/storage/' . $booking->design_photo : null, + 'repair_photo' => $booking->repair_photo ? '/storage/' . $booking->repair_photo : null, + 'repair_details' => $booking->repair_details, + 'repair_notes' => $booking->repair_notes, + 'category' => $booking->category + ]); + } else if (in_array($status, ['reservasi', 'dikonfirmasi'])) { + $data = array_merge($data, [ + 'service_type' => $booking->service_type, + 'category' => $booking->category, + 'appointment_date' => Carbon::parse($booking->appointment_date)->format('Y-m-d'), + 'appointment_time' => $booking->appointment_time, + 'design_photo' => $booking->design_photo ? '/storage/' . $booking->design_photo : null, + 'notes' => $booking->notes, + 'status' => $status === 'reservasi' ? 'Menunggu Konfirmasi' : 'Dikonfirmasi', + 'status_code' => $status + ]); + } + + return $data; + }); + + return $this->sendResponse([ + 'bookings' => $bookings, + 'total' => $bookings->count() + ], 'Daftar pesanan berhasil diambil'); + + } catch (\Exception $e) { + \Log::error('Error getting bookings: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data pesanan'], 500); + } + } + + /** + * Get completed booking details with measurements + */ + public function getCompletedBookingDetails(Booking $booking) + { + try { + // Check if user is authorized to view this booking + if ($booking->customer_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses ke pesanan ini'], 403); + } + + // Check if booking is completed + if ($booking->status !== 'selesai') { + return $this->sendError('Invalid status', ['error' => 'Pesanan belum selesai'], 422); + } + + // Load relationships and measurements + $booking->load(['tailor:id,name,profile_photo']); + + $response = [ + 'id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'tailor_name' => $booking->tailor->name, + 'tailor_photo' => $booking->tailor->profile_photo, + 'service_type' => $booking->service_type, + 'category' => $booking->category, + 'appointment_date' => Carbon::parse($booking->appointment_date)->format('Y-m-d'), + 'completed_at' => $booking->completed_at ? Carbon::parse($booking->completed_at)->format('Y-m-d') : null, + 'total_price' => $booking->total_price ?? 0, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'measurements' => $booking->measurements ?? [], + 'completion_photo' => $booking->completion_photo, + 'completion_notes' => $booking->completion_notes, + 'pickup_date' => $booking->pickup_date + ]; + + return $this->sendResponse($response, 'Detail pesanan selesai berhasil diambil'); + + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil detail pesanan'], 500); + } + } + + /** + * Process final payment and set pickup date for completed booking + */ + public function processCompletionPayment(Request $request, Booking $booking) + { + try { + // Add debugging + \Log::info('Attempting completion payment', [ + 'booking_id' => $booking->id, + 'status' => $booking->status, + 'payment_status' => $booking->payment_status, + 'tailor_id' => $booking->tailor_id, + 'auth_id' => Auth::id() + ]); + + // Check if user is authorized (penjahit) + if ($booking->tailor_id !== Auth::id()) { + \Log::warning('Unauthorized payment attempt', [ + 'booking_id' => $booking->id, + 'tailor_id' => $booking->tailor_id, + 'auth_id' => Auth::id() + ]); + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk menandai pembayaran selesai'], 403); + } + + // Validate booking status + if ($booking->status !== 'selesai') { + \Log::warning('Invalid booking status for payment', [ + 'booking_id' => $booking->id, + 'status' => $booking->status + ]); + return $this->sendError('Invalid status', ['error' => 'Pembayaran hanya dapat dilakukan untuk pesanan yang sudah selesai'], 422); + } + + // Check if already paid + if ($booking->payment_status === 'paid' || $booking->payment_status === 'success') { + \Log::warning('Booking already paid', ['booking_id' => $booking->id]); + return $this->sendError('Already paid', ['error' => 'Pesanan ini sudah dibayar'], 422); + } + + // Validate request + $validator = Validator::make($request->all(), [ + 'pickup_date' => 'required|date|after_or_equal:today' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Update booking with payment and pickup date + if ($booking->payment_method === 'COD') { + $booking->payment_status = 'success'; + } else { + $booking->payment_status = 'paid'; + } + $booking->pickup_date = $request->pickup_date; + $booking->save(); + + // Load customer for response + $booking->load('customer:id,name,phone_number'); + + return $this->sendResponse([ + 'booking' => [ + 'id' => $booking->id, + 'customer_name' => $booking->customer->name, + 'customer_phone' => $booking->customer->phone_number, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'status' => $booking->status, + 'pickup_date' => Carbon::parse($booking->pickup_date)->format('Y-m-d') + ], + 'message' => 'Pembayaran telah dikonfirmasi oleh penjahit', + 'pickup_info' => [ + 'date' => Carbon::parse($booking->pickup_date)->format('Y-m-d'), + 'status' => 'Sudah dibayar dengan status ' . $booking->payment_status + ] + ], 'Pembayaran telah dikonfirmasi dan tanggal pengambilan berhasil diatur'); + + } catch (\Exception $e) { + \Log::error('Error processing completion payment: ' . $e->getMessage(), [ + 'booking_id' => $booking->id, + 'exception' => $e + ]); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memproses pembayaran'], 500); + } + } + + /** + * Get all bookings (Admin only) + * + * @param Request $request + * @return JsonResponse + */ + public function getAllBookings(Request $request): JsonResponse + { + $status = $request->query('status'); + $perPage = $request->query('per_page', 10); + + $query = Booking::with(['customer', 'tailor']) + ->orderBy('created_at', 'desc'); + + if ($status) { + $query->where('status', $status); + } + + $bookings = $query->paginate($perPage); + + return response()->json([ + 'status' => 'success', + 'message' => 'Bookings retrieved successfully', + 'data' => $bookings + ]); + } + + /** + * Update booking price and completion date + * + * @param Request $request + * @param Booking $booking + * @return JsonResponse + */ + public function updatePrice(Request $request, Booking $booking): JsonResponse + { + try { + // Check if the authenticated user is the tailor of this booking + if ($booking->tailor_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengubah harga booking ini'], 403); + } + + // Validate request + $validator = Validator::make($request->all(), [ + 'total_price' => 'required|numeric|min:0', + 'completion_date' => 'required|date|after_or_equal:today' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Update price and completion date + $booking->total_price = $request->total_price; + $booking->completion_date = $request->completion_date; + $booking->save(); + + return $this->sendResponse([ + 'id' => $booking->id, + 'total_price' => $booking->total_price, + 'completion_date' => Carbon::parse($booking->completion_date)->format('Y-m-d'), + 'status' => $booking->status, + 'customer' => [ + 'name' => $booking->customer->name, + 'phone_number' => $booking->customer->phone_number + ] + ], 'Harga dan tanggal selesai pesanan berhasil diupdate'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate harga dan tanggal selesai pesanan'], 500); + } + } + + /** + * Generate unique transaction code + * + * @return string + */ + private function generateTransactionCode() + { + // Format: TRX-{YYYYMMDD}-{6 random characters} + $date = Carbon::now()->format('Ymd'); + $random = strtoupper(substr(md5(uniqid()), 0, 6)); + $code = "TRX-{$date}-{$random}"; + + // Check if code already exists, if so, regenerate + while (Booking::where('transaction_code', $code)->exists()) { + $random = strtoupper(substr(md5(uniqid()), 0, 6)); + $code = "TRX-{$date}-{$random}"; + } + + return $code; + } +} diff --git a/TA_API/app/Http/Controllers/Api/CustomerController.php b/TA_API/app/Http/Controllers/Api/CustomerController.php new file mode 100644 index 0000000..2503dc0 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/CustomerController.php @@ -0,0 +1,280 @@ +with(['customerBookings', 'preferredSpecializations', 'givenRatings']) + ->get() + ->map(function ($customer) { + return [ + 'id' => $customer->id, + 'name' => $customer->name, + 'email' => $customer->email, + 'phone_number' => $customer->phone_number, + 'address' => $customer->address, + 'profile_photo' => $customer->profile_photo, + 'location' => [ + 'latitude' => $customer->latitude, + 'longitude' => $customer->longitude + ], + 'preferred_specializations' => $customer->preferredSpecializations->map(function ($spec) { + return [ + 'id' => $spec->id, + 'name' => $spec->name, + 'photo' => $spec->photo + ]; + }), + 'bookings' => [ + 'total' => $customer->customerBookings->count(), + 'completed' => $customer->customerBookings->where('status', 'completed')->count(), + 'recent' => $customer->customerBookings->take(5)->map(function ($booking) { + return [ + 'id' => $booking->id, + 'tailor_name' => $booking->tailor->name ?? 'Unknown', + 'status' => $booking->status, + 'appointment_date' => $booking->appointment_date, + 'total_price' => $booking->total_price + ]; + }) + ], + 'ratings_given' => [ + 'total' => $customer->givenRatings->count(), + 'average_rating' => round($customer->givenRatings->avg('rating') ?? 0, 1), + 'recent' => $customer->givenRatings->take(5)->map(function ($rating) { + return [ + 'rating' => $rating->rating, + 'review' => $rating->review, + 'tailor_name' => $rating->tailor->name ?? 'Unknown', + 'created_at' => $rating->created_at + ]; + }) + ], + 'created_at' => $customer->created_at, + 'updated_at' => $customer->updated_at + ]; + }); + + return response()->json([ + 'status' => 'success', + 'data' => $customers + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Failed to retrieve customers data', + 'error' => $e->getMessage() + ], 500); + } + } + + public function getCustomerDetail($id) + { + try { + $customer = User::where('role', 'pelanggan') + ->with(['customerBookings.tailor', 'preferredSpecializations', 'givenRatings.tailor']) + ->findOrFail($id); + + $data = [ + 'id' => $customer->id, + 'name' => $customer->name, + 'email' => $customer->email, + 'phone_number' => $customer->phone_number, + 'address' => $customer->address, + 'profile_photo' => $customer->profile_photo, + 'location' => [ + 'latitude' => $customer->latitude, + 'longitude' => $customer->longitude + ], + 'preferred_specializations' => $customer->preferredSpecializations->map(function ($spec) { + return [ + 'id' => $spec->id, + 'name' => $spec->name, + 'photo' => $spec->photo + ]; + }), + 'bookings' => [ + 'total' => $customer->customerBookings->count(), + 'completed' => $customer->customerBookings->where('status', 'completed')->count(), + 'history' => $customer->customerBookings->map(function ($booking) { + return [ + 'id' => $booking->id, + 'tailor_name' => $booking->tailor->name ?? 'Unknown', + 'status' => $booking->status, + 'appointment_date' => $booking->appointment_date, + 'total_price' => $booking->total_price, + 'service_type' => $booking->service_type, + 'notes' => $booking->notes, + 'created_at' => $booking->created_at + ]; + }) + ], + 'ratings_given' => [ + 'total' => $customer->givenRatings->count(), + 'average_rating' => round($customer->givenRatings->avg('rating') ?? 0, 1), + 'history' => $customer->givenRatings->map(function ($rating) { + return [ + 'rating' => $rating->rating, + 'review' => $rating->review, + 'tailor_name' => $rating->tailor->name ?? 'Unknown', + 'created_at' => $rating->created_at + ]; + }) + ], + 'created_at' => $customer->created_at, + 'updated_at' => $customer->updated_at + ]; + + return response()->json([ + 'status' => 'success', + 'data' => $data + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Failed to retrieve customer detail', + 'error' => $e->getMessage() + ], 500); + } + } + + public function getCustomerTransactions($id) + { + try { + $customer = User::where('role', 'pelanggan') + ->with(['customerBookings.tailor']) + ->findOrFail($id); + + $transactions = $customer->customerBookings->map(function ($booking) { + return [ + 'booking_id' => $booking->id, + 'tailor_name' => $booking->tailor->name ?? 'Unknown', + 'status' => $booking->status, + 'appointment_date' => $booking->appointment_date, + 'service_type' => $booking->service_type, + 'total_price' => $booking->total_price, + 'payment_status' => $booking->payment_status, + 'notes' => $booking->notes, + 'created_at' => $booking->created_at + ]; + }); + + return response()->json([ + 'status' => 'success', + 'data' => [ + 'customer_id' => $customer->id, + 'customer_name' => $customer->name, + 'total_transactions' => $transactions->count(), + 'total_spent' => $transactions->where('payment_status', 'paid')->sum('total_price'), + 'transactions' => $transactions + ] + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal mengambil data transaksi pelanggan', + 'error' => $e->getMessage() + ], 500); + } + } + + public function updateCustomerSpecializations(Request $request, $id) + { + try { + // Validasi input + $request->validate([ + 'specialization_ids' => 'required|array', + 'specialization_ids.*' => 'exists:tailor_specializations,id' + ]); + + // Cari pelanggan + $customer = User::where('role', 'pelanggan')->find($id); + + if (!$customer) { + return response()->json([ + 'status' => 'error', + 'message' => 'Pelanggan tidak ditemukan' + ], 404); + } + + // Sync specializations + $customer->preferredSpecializations()->sync($request->specialization_ids); + + // Load ulang relasi untuk memastikan data terbaru + $customer->load('preferredSpecializations'); + + return response()->json([ + 'status' => 'success', + 'message' => 'Spesialisasi pelanggan berhasil diperbarui', + 'data' => [ + 'customer_id' => $customer->id, + 'customer_name' => $customer->name, + 'specializations' => $customer->preferredSpecializations->map(function ($spec) { + return [ + 'id' => $spec->id, + 'name' => $spec->name, + 'icon' => $spec->icon + ]; + }) + ] + ]); + + } catch (\Illuminate\Validation\ValidationException $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Validasi gagal', + 'errors' => $e->errors() + ], 422); + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal memperbarui spesialisasi pelanggan', + 'error' => $e->getMessage() + ], 500); + } + } + + public function deleteCustomer($id) + { + try { + $customer = User::where('role', 'pelanggan')->find($id); + + if (!$customer) { + return response()->json([ + 'status' => 'error', + 'message' => 'Pelanggan tidak ditemukan' + ], 404); + } + + // Hapus relasi spesialisasi terlebih dahulu + $customer->preferredSpecializations()->detach(); + + // Hapus customer + $customer->delete(); + + return response()->json([ + 'status' => 'success', + 'message' => 'Pelanggan berhasil dihapus' + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal menghapus pelanggan', + 'error' => $e->getMessage() + ], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/DocumentationController.php b/TA_API/app/Http/Controllers/Api/DocumentationController.php new file mode 100644 index 0000000..a090813 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/DocumentationController.php @@ -0,0 +1,47 @@ + File::get(base_path('docs/wallet-api.md')), + // Add other documentation sections here + ]; + + return response()->json([ + 'success' => true, + 'data' => $docs, + 'message' => 'API documentation retrieved successfully' + ]); + } + + public function show($section) + { + $path = base_path("docs/{$section}-api.md"); + + if (!File::exists($path)) { + return response()->json([ + 'success' => false, + 'message' => 'Documentation section not found' + ], 404); + } + + $content = File::get($path); + + return response()->json([ + 'success' => true, + 'data' => [ + 'section' => $section, + 'content' => $content + ], + 'message' => 'API documentation section retrieved successfully' + ]); + } +} diff --git a/TA_API/app/Http/Controllers/Api/EmailVerificationController.php b/TA_API/app/Http/Controllers/Api/EmailVerificationController.php new file mode 100644 index 0000000..9c44139 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/EmailVerificationController.php @@ -0,0 +1,101 @@ +user()->hasVerifiedEmail()) { + return $this->sendResponse([], 'Email sudah terverifikasi.'); + } + + // Generate verification URL + $verificationUrl = $this->generateVerificationUrl($request->user()); + + // Send custom verification email + $request->user()->notify(new \App\Notifications\VerifyEmailNotification($verificationUrl)); + + return $this->sendResponse([ + 'verification_url' => $verificationUrl + ], 'Link verifikasi email telah dikirim.'); + } + + /** + * Verify email + */ + public function verify(Request $request, $id) + { + if (!URL::hasValidSignature($request)) { + return response()->view('emails.verification-error', [ + 'message' => 'Link verifikasi tidak valid atau sudah kadaluarsa.' + ], 400); + } + + $user = User::find($id); + + if (!$user) { + return response()->view('emails.verification-error', [ + 'message' => 'Pengguna tidak ditemukan.' + ], 404); + } + + if ($user->hasVerifiedEmail()) { + return response()->view('emails.verification-success', [ + 'message' => 'Email sudah diverifikasi sebelumnya.', + 'user' => $user + ]); + } + + if ($user->markEmailAsVerified()) { + event(new Verified($user)); + } + + return response()->view('emails.verification-success', [ + 'message' => 'Email berhasil diverifikasi.', + 'user' => $user + ]); + } + + /** + * Resend verification email + */ + public function resend(Request $request) + { + if ($request->user()->hasVerifiedEmail()) { + return $this->sendResponse([], 'Email sudah terverifikasi.'); + } + + // Generate verification URL + $verificationUrl = $this->generateVerificationUrl($request->user()); + + // Send custom verification email + $request->user()->notify(new \App\Notifications\VerifyEmailNotification($verificationUrl)); + + return $this->sendResponse([ + 'verification_url' => $verificationUrl + ], 'Link verifikasi email telah dikirim ulang.'); + } + + /** + * Generate verification URL + */ + protected function generateVerificationUrl($user) + { + // Generate verification URL yang langsung mengarah ke API backend + return URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), // Link expires in 60 minutes + ['id' => $user->id, 'hash' => sha1($user->email)] + ); + } +} diff --git a/TA_API/app/Http/Controllers/Api/ForgotPasswordController.php b/TA_API/app/Http/Controllers/Api/ForgotPasswordController.php new file mode 100644 index 0000000..82546ce --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/ForgotPasswordController.php @@ -0,0 +1,126 @@ +all(), [ + 'email' => 'required|email', + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Check if user exists and has the correct role based on the endpoint + $user = User::where('email', $request->email)->first(); + $path = request()->path(); + $requiredRole = str_contains($path, 'penjahit') ? 'penjahit' : 'pelanggan'; + + if (!$user || $user->role !== $requiredRole) { + return $this->sendError('Error.', ['email' => 'Email tidak ditemukan'], 404); + } + + // Generate 6-digit PIN + $pin = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT); + + // Store PIN in password_resets table + DB::table('password_resets')->updateOrInsert( + ['email' => $user->email], + [ + 'token' => $pin, + 'created_at' => Carbon::now() + ] + ); + + // Send custom reset password email with PIN + $user->notify(new \App\Notifications\ResetPasswordNotification($pin)); + + return $this->sendResponse([ + 'message' => 'PIN reset password telah dikirim ke email Anda' + ], 'Kami sudah mengirim PIN reset password ke email Anda'); + } + + /** + * Reset password + */ + public function reset(Request $request) + { + $validator = Validator::make($request->all(), [ + 'pin' => 'required|digits:6', + 'email' => 'required|email', + 'password' => 'required|confirmed|min:8', + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Check if user exists and has the correct role based on the endpoint + $user = User::where('email', $request->email)->first(); + $path = request()->path(); + $requiredRole = str_contains($path, 'penjahit') ? 'penjahit' : 'pelanggan'; + + if (!$user || $user->role !== $requiredRole) { + return $this->sendError('Error.', ['email' => 'Email tidak ditemukan'], 404); + } + + // Check if PIN exists and is valid + $passwordReset = DB::table('password_resets') + ->where('email', $user->email) + ->where('token', $request->pin) + ->first(); + + if (!$passwordReset) { + return $this->sendError('Error.', ['pin' => 'PIN tidak valid atau sudah kadaluarsa'], 400); + } + + // Check if PIN is expired (60 minutes) + $createdAt = Carbon::parse($passwordReset->created_at); + if ($createdAt->addMinutes(60)->isPast()) { + DB::table('password_resets')->where('email', $user->email)->delete(); + return $this->sendError('Error.', ['pin' => 'PIN sudah kadaluarsa'], 400); + } + + // Update password + $user->password = Hash::make($request->password); + $user->save(); + + // Delete PIN + DB::table('password_resets')->where('email', $user->email)->delete(); + + // Fire password reset event + event(new PasswordReset($user)); + + return $this->sendResponse([], 'Password berhasil direset'); + } + + /** + * Generate reset password URL + */ + protected function generateResetUrl($user, $token) + { + // Get frontend URL from config or env + $frontendUrl = config('app.frontend_url', env('FRONTEND_URL', 'http://localhost:3000')); + + // Combine with frontend URL + return $frontendUrl . '/reset-password?email=' . urlencode($user->email) . '&token=' . $token; + } +} diff --git a/TA_API/app/Http/Controllers/Api/MidtransController.php b/TA_API/app/Http/Controllers/Api/MidtransController.php new file mode 100644 index 0000000..ecaf15d --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/MidtransController.php @@ -0,0 +1,330 @@ +customer_id) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk melakukan pembayaran ini'], 403); + } + + // Periksa status booking + if (!in_array($booking->status, ['reservasi', 'diproses', 'selesai'])) { + return $this->sendError('Invalid status', ['error' => 'Pesanan tidak dapat dibayar dengan status saat ini'], 422); + } + + // Periksa jika pembayaran sudah dilakukan + if (in_array($booking->payment_status, ['paid', 'success'])) { + return $this->sendError('Already paid', ['error' => 'Pesanan ini sudah dibayar'], 422); + } + + // Pastikan harga telah diatur + if (!$booking->total_price) { + return $this->sendError('Invalid price', ['error' => 'Harga belum ditetapkan oleh penjahit'], 422); + } + + // Set up parameter untuk Midtrans + $params = [ + 'transaction_details' => [ + 'order_id' => $booking->transaction_code, // Gunakan transaction_code yang sudah ada + 'gross_amount' => (int) ($booking->total_price + 4000), // Tambahkan biaya admin + ], + 'customer_details' => [ + 'first_name' => $booking->customer->name, + 'email' => $booking->customer->email, + 'phone' => $booking->customer->phone_number ?? '', + ], + 'item_details' => [ + [ + 'id' => 'BOOKING-' . $booking->id, + 'price' => (int) $booking->total_price, + 'quantity' => 1, + 'name' => 'Booking ' . $booking->service_type . ' - ' . $booking->category, + ], + [ + 'id' => 'ADMIN-FEE', + 'price' => 4000, + 'quantity' => 1, + 'name' => 'Biaya Admin (Payment Gateway + TailorHub)', + ] + ], + // CATATAN PENTING: Jangan aktifkan baris di bawah ini jika ingin menampilkan semua metode pembayaran + // Jika ingin membatasi metode pembayaran tertentu, uncomment baris di bawah ini + // 'enabled_payments' => ['bank_transfer'], + ]; + + // Buat token transaksi Snap + $snapToken = Snap::getSnapToken($params); + + // Simpan informasi pembayaran + $booking->update([ + 'payment_method' => 'transfer_bank_midtrans', + 'midtrans_snap_token' => $snapToken + ]); + + return $this->sendResponse([ + 'snap_token' => $snapToken, + 'redirect_url' => 'https://app.sandbox.midtrans.com/snap/v2/vtweb/' . $snapToken, + 'booking' => [ + 'id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'total_price' => $booking->total_price, + 'status' => $booking->status, + ] + ], 'Token pembayaran berhasil dibuat'); + + } catch (\Exception $e) { + \Log::error('Error initiating Midtrans payment: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memulai pembayaran: ' . $e->getMessage()], 500); + } + } + + /** + * Callback notification handler dari Midtrans + */ + public function notificationHandler(Request $request) + { + try { + $notificationBody = $request->all(); + \Log::info('Midtrans Notification Received', $notificationBody); + + // Verifikasi signature menggunakan server key untuk keamanan + $notification = new Notification(); + + $transactionStatus = $notification->transaction_status; + $type = $notification->payment_type; + $orderId = $notification->order_id; + $fraud = $notification->fraud_status; + + // Cari booking berdasarkan transaction_code (order_id) + $booking = Booking::where('transaction_code', $orderId)->first(); + + if (!$booking) { + return response()->json(['status' => 'error', 'message' => 'Booking tidak ditemukan'], 404); + } + + // Proses berdasarkan status transaksi + if ($transactionStatus == 'capture') { + if ($type == 'credit_card'){ + if($fraud == 'challenge'){ + $booking->payment_status = 'pending'; + } else { + $booking->payment_status = 'paid'; + // Tambahkan dana ke wallet penjahit + $tailorWallet = $booking->tailor->wallet; + if (!$tailorWallet) { + $tailorWallet = Wallet::create([ + 'user_id' => $booking->tailor_id, + 'balance' => 0 + ]); + } + $tailorWallet->addBalance( + $booking->total_price, + 'Pembayaran booking #' . $booking->transaction_code, + $booking + ); + } + } + } + else if ($transactionStatus == 'settlement') { + $booking->payment_status = 'paid'; + // Tambahkan dana ke wallet penjahit + $tailorWallet = $booking->tailor->wallet; + if (!$tailorWallet) { + $tailorWallet = Wallet::create([ + 'user_id' => $booking->tailor_id, + 'balance' => 0 + ]); + } + $tailorWallet->addBalance( + $booking->total_price, + 'Pembayaran booking #' . $booking->transaction_code, + $booking + ); + } + else if ($transactionStatus == 'pending') { + $booking->payment_status = 'pending'; + } + else if ($transactionStatus == 'deny') { + $booking->payment_status = 'failed'; + } + else if ($transactionStatus == 'expire') { + $booking->payment_status = 'expired'; + } + else if ($transactionStatus == 'cancel') { + $booking->payment_status = 'cancelled'; + } + + // Simpan perubahan + $booking->save(); + + \Log::info('Payment status updated: ' . $booking->payment_status); + + return response()->json(['status' => 'success', 'message' => 'Notification processed']); + + } catch (\Exception $e) { + \Log::error('Error processing Midtrans notification: ' . $e->getMessage()); + return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500); + } + } + + /** + * Memeriksa status pembayaran + */ + public function checkPaymentStatus(Booking $booking) + { + try { + // Periksa otentikasi dan otorisasi + if (Auth::id() !== $booking->customer_id && Auth::id() !== $booking->tailor_id) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk melihat status pembayaran ini'], 403); + } + + return $this->sendResponse([ + 'booking_id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'total_price' => $booking->total_price, + 'status' => $booking->status, + 'midtrans_snap_token' => $booking->midtrans_snap_token + ], 'Status pembayaran berhasil diambil'); + + } catch (\Exception $e) { + \Log::error('Error checking payment status: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memeriksa status pembayaran'], 500); + } + } + + /** + * Memeriksa dan memperbarui status pembayaran secara manual + * Dapat digunakan sebagai alternatif notification handler Midtrans + */ + public function manualCheckStatus(Booking $booking) + { + try { + // Periksa otentikasi dan otorisasi + // User harus customer atau penjahit terkait atau admin + $user = Auth::user(); + if ($user->id !== $booking->customer_id && $user->id !== $booking->tailor_id && !$user->hasRole('admin')) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk memeriksa status pembayaran ini'], 403); + } + + // Periksa apakah booking memiliki transaction_code + if (!$booking->transaction_code) { + return $this->sendError('Invalid order', ['error' => 'Booking ini tidak memiliki kode transaksi'], 422); + } + + // Periksa status transaksi di Midtrans + $statusResponse = Transaction::status($booking->transaction_code); + + \Log::info('Midtrans Status Check Response', (array) $statusResponse); + + $transactionStatus = $statusResponse->transaction_status ?? null; + $fraudStatus = $statusResponse->fraud_status ?? null; + $paymentType = $statusResponse->payment_type ?? null; + + // Jika status sudah paid, tidak perlu update lagi + if (in_array($booking->payment_status, ['paid', 'success']) && $transactionStatus == 'settlement') { + return $this->sendResponse([ + 'booking_id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'midtrans_status' => $transactionStatus, + ], 'Pembayaran sudah berhasil'); + } + + // Update status pembayaran berdasarkan response + $statusUpdated = false; + + if ($transactionStatus == 'capture') { + if ($paymentType == 'credit_card') { + if ($fraudStatus == 'challenge') { + $booking->payment_status = 'pending'; + } else { + $booking->payment_status = 'paid'; + $statusUpdated = true; + } + } + } + else if ($transactionStatus == 'settlement') { + $booking->payment_status = 'paid'; + $statusUpdated = true; + } + else if ($transactionStatus == 'pending') { + $booking->payment_status = 'pending'; + } + else if ($transactionStatus == 'deny') { + $booking->payment_status = 'failed'; + } + else if ($transactionStatus == 'expire') { + $booking->payment_status = 'expired'; + } + else if ($transactionStatus == 'cancel') { + $booking->payment_status = 'cancelled'; + } + + // Jika status berubah menjadi paid, tambahkan dana ke wallet penjahit + if ($statusUpdated && $booking->payment_status == 'paid') { + $tailorWallet = $booking->tailor->wallet; + if (!$tailorWallet) { + $tailorWallet = Wallet::create([ + 'user_id' => $booking->tailor_id, + 'balance' => 0 + ]); + } + $tailorWallet->addBalance( + $booking->total_price, + 'Pembayaran booking #' . $booking->transaction_code, + $booking + ); + } + + // Simpan perubahan + $booking->save(); + + \Log::info('Payment status manually updated: ' . $booking->payment_status); + + return $this->sendResponse([ + 'booking_id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'total_price' => $booking->total_price, + 'status' => $booking->status, + 'midtrans_status' => $transactionStatus, + 'midtrans_snap_token' => $booking->midtrans_snap_token + ], 'Status pembayaran berhasil diperbarui'); + + } catch (\Exception $e) { + \Log::error('Error checking payment status manually: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memeriksa status pembayaran: ' . $e->getMessage()], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/RatingController.php b/TA_API/app/Http/Controllers/Api/RatingController.php new file mode 100644 index 0000000..16749dc --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/RatingController.php @@ -0,0 +1,110 @@ +all(), [ + 'rating' => 'required|numeric|min:0|max:5', + 'review' => 'nullable|string|max:1000' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + try { + // Check if booking belongs to the authenticated user + if ($booking->customer_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk memberikan rating pada booking ini'], 403); + } + + // Check if booking is completed + if ($booking->status !== 'selesai') { + return $this->sendError('Error validasi.', ['error' => 'Anda hanya dapat memberikan rating untuk pesanan yang telah selesai'], 422); + } + + // Check if rating already exists + if (TailorRating::where('booking_id', $booking->id)->where('customer_id', Auth::id())->exists()) { + return $this->sendError('Error validasi.', ['error' => 'Anda sudah memberikan rating untuk pesanan ini'], 422); + } + + $rating = TailorRating::create([ + 'booking_id' => $booking->id, + 'customer_id' => Auth::id(), + 'tailor_id' => $booking->tailor_id, + 'rating' => $request->rating, + 'review' => $request->review + ]); + + return $this->sendResponse($rating, 'Rating berhasil ditambahkan.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menambahkan rating'], 500); + } + } + + /** + * Get tailor's ratings + */ + public function getTailorRatings($tailorId) + { + try { + $ratings = TailorRating::where('tailor_id', $tailorId) + ->with(['customer:id,name', 'booking']) + ->orderBy('created_at', 'desc') + ->get(); + + $averageRating = $ratings->avg('rating'); + + return $this->sendResponse([ + 'ratings' => $ratings, + 'average_rating' => round($averageRating, 1), + 'total_ratings' => $ratings->count() + ], 'Data rating berhasil diambil.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data rating'], 500); + } + } + + /** + * Update a rating + */ + public function update(Request $request, TailorRating $rating) + { + $validator = Validator::make($request->all(), [ + 'rating' => 'required|numeric|min:0|max:5', + 'review' => 'nullable|string|max:1000' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + try { + // Check if rating belongs to the authenticated user + if ($rating->customer_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengubah rating ini'], 403); + } + + $rating->update([ + 'rating' => $request->rating, + 'review' => $request->review + ]); + + return $this->sendResponse($rating, 'Rating berhasil diupdate.'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate rating'], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorCalendarController.php b/TA_API/app/Http/Controllers/Api/TailorCalendarController.php new file mode 100644 index 0000000..41b9eee --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorCalendarController.php @@ -0,0 +1,207 @@ + $month, + 'year' => $year, + 'user_id' => Auth::id(), + 'user_role' => Auth::user()->role + ]); + + // Validate month and year + if (!is_numeric($month) || !is_numeric($year) || + $month < 1 || $month > 12 || + $year < 2024 || $year > 2100) { + \Log::warning('Invalid date parameters', [ + 'month' => $month, + 'year' => $year + ]); + return $this->sendError('Invalid date', ['error' => 'Bulan atau tahun tidak valid'], 422); + } + + // Create Carbon instances for start and end of month + try { + $startOfMonth = Carbon::create($year, $month, 1)->startOfMonth(); + $endOfMonth = Carbon::create($year, $month, 1)->endOfMonth(); + + \Log::info('Date range:', [ + 'start' => $startOfMonth->format('Y-m-d'), + 'end' => $endOfMonth->format('Y-m-d') + ]); + } catch (\Exception $e) { + \Log::error('Date creation error:', [ + 'message' => $e->getMessage(), + 'month' => $month, + 'year' => $year + ]); + return $this->sendError('Invalid date', ['error' => 'Format tanggal tidak valid'], 422); + } + + // Get all bookings for the month + $bookings = Booking::where('tailor_id', Auth::id()) + ->whereBetween('appointment_date', [ + $startOfMonth->format('Y-m-d'), + $endOfMonth->format('Y-m-d') + ]) + ->with(['customer:id,name,phone_number']) + ->orderBy('appointment_date') + ->orderBy('appointment_time') + ->get(); + + \Log::info('Bookings found:', [ + 'count' => $bookings->count(), + 'date_range' => [ + $startOfMonth->format('Y-m-d'), + $endOfMonth->format('Y-m-d') + ] + ]); + + // Initialize calendar array + $calendar = []; + $currentDate = $startOfMonth->copy(); + + // Initialize all dates of the month + while ($currentDate <= $endOfMonth) { + $dateStr = $currentDate->format('Y-m-d'); + $calendar[$dateStr] = [ + 'date' => $dateStr, + 'day' => $currentDate->format('d'), + 'day_name' => $currentDate->isoFormat('dddd'), + 'bookings' => [] + ]; + $currentDate->addDay(); + } + + // Add bookings to their respective dates + foreach ($bookings as $booking) { + $date = Carbon::parse($booking->appointment_date)->format('Y-m-d'); + if (isset($calendar[$date])) { + $calendar[$date]['bookings'][] = [ + 'id' => $booking->id, + 'time' => $booking->appointment_time, + 'customer_name' => $booking->customer->name, + 'customer_phone' => $booking->customer->phone_number, + 'service_type' => $booking->service_type, + 'category' => $booking->category, + 'status' => $booking->status, + 'payment_status' => $booking->payment_status + ]; + } + } + + // Get month summary + $summary = [ + 'total_bookings' => $bookings->count(), + 'pending_bookings' => $bookings->where('status', 'reservasi')->count(), + 'ongoing_bookings' => $bookings->where('status', 'diproses')->count(), + 'completed_bookings' => $bookings->where('status', 'selesai')->count(), + 'cancelled_bookings' => $bookings->where('status', 'dibatalkan')->count(), + ]; + + \Log::info('Calendar response prepared', [ + 'total_dates' => count($calendar), + 'summary' => $summary + ]); + + return $this->sendResponse([ + 'month' => (int)$month, + 'year' => (int)$year, + 'month_name' => Carbon::create($year, $month, 1)->isoFormat('MMMM'), + 'calendar' => array_values($calendar), + 'summary' => $summary + ], 'Data kalender berhasil diambil'); + + } catch (\Exception $e) { + \Log::error('Calendar error:', [ + 'message' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'trace' => $e->getTraceAsString() + ]); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data kalender: ' . $e->getMessage()], 500); + } + } + + /** + * Get bookings for specific date + */ + public function getDateBookings($date) + { + try { + // Validate date format + try { + $bookingDate = Carbon::parse($date); + } catch (\Exception $e) { + return $this->sendError('Invalid date', ['error' => 'Format tanggal tidak valid'], 422); + } + + // Get all bookings for the date + $bookings = Booking::where('tailor_id', Auth::id()) + ->whereDate('appointment_date', $bookingDate->format('Y-m-d')) + ->with([ + 'customer:id,name,phone_number,address' + ]) + ->orderBy('appointment_time') + ->get(); + + // Format bookings with detailed information + $formattedBookings = $bookings->map(function ($booking) { + return [ + 'id' => $booking->id, + 'transaction_code' => $booking->transaction_code, + 'time' => $booking->appointment_time, + 'customer' => [ + 'name' => $booking->customer->name, + 'phone' => $booking->customer->phone_number, + 'address' => $booking->customer->address + ], + 'service_type' => $booking->service_type, + 'category' => $booking->category, + 'status' => $booking->status, + 'payment_status' => $booking->payment_status, + 'payment_method' => $booking->payment_method, + 'notes' => $booking->notes, + 'measurements' => $booking->measurements, + 'total_price' => $booking->total_price, + 'design_photo' => $booking->design_photo ? url('storage/designs/' . $booking->design_photo) : null, + 'completion_photo' => $booking->completion_photo ? url('storage/completions/' . $booking->completion_photo) : null + ]; + }); + + // Get day summary + $summary = [ + 'total_bookings' => $bookings->count(), + 'pending_bookings' => $bookings->where('status', 'reservasi')->count(), + 'ongoing_bookings' => $bookings->where('status', 'diproses')->count(), + 'completed_bookings' => $bookings->where('status', 'selesai')->count(), + 'cancelled_bookings' => $bookings->where('status', 'dibatalkan')->count(), + ]; + + return $this->sendResponse([ + 'date' => $bookingDate->format('Y-m-d'), + 'day_name' => $bookingDate->isoFormat('dddd'), + 'bookings' => $formattedBookings, + 'summary' => $summary + ], 'Data pesanan tanggal ' . $bookingDate->format('Y-m-d') . ' berhasil diambil'); + + } catch (\Exception $e) { + \Log::error('Calendar date error: ' . $e->getMessage()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data pesanan: ' . $e->getMessage()], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorController.php b/TA_API/app/Http/Controllers/Api/TailorController.php new file mode 100644 index 0000000..f1b6074 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorController.php @@ -0,0 +1,268 @@ +withAvg('ratings as average_rating', 'rating') + ->having('average_rating', '>', 2.5) + ->orWhereNull('average_rating') + ->with(['specializations', 'services', 'ratings']) + ->get() + ->map(function ($tailor) { + return [ + 'id' => $tailor->id, + 'name' => $tailor->name, + 'email' => $tailor->email, + 'phone' => $tailor->phone_number, + 'profile' => [ + 'shop_name' => $tailor->name, + 'address' => $tailor->address, + 'description' => $tailor->shop_description, + 'photo' => $tailor->profile_photo, + 'latitude' => $tailor->latitude, + 'longitude' => $tailor->longitude + ], + 'specializations' => $tailor->specializations->map(function ($specialization) { + return [ + 'id' => $specialization->id, + 'name' => $specialization->name, + 'photo' => $specialization->photo + ]; + }), + 'services' => $tailor->services->map(function ($service) { + return [ + 'id' => $service->id, + 'name' => $service->name, + 'price' => $service->price, + 'description' => $service->description, + 'is_available' => $service->is_available + ]; + }), + 'ratings' => [ + 'average_rating' => round($tailor->average_rating ?? 0, 1), + 'total_ratings' => $tailor->ratings->count(), + 'reviews' => $tailor->ratings->map(function ($rating) { + return [ + 'rating' => $rating->rating, + 'comment' => $rating->review, + 'created_at' => $rating->created_at + ]; + }) + ] + ]; + }); + + return response()->json([ + 'status' => 'success', + 'data' => $tailors + ]); + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Failed to retrieve tailors data', + 'error' => $e->getMessage() + ], 500); + } + } + + // Method untuk mendapatkan semua penjahit tanpa filter rating + public function getAllTailorsNoFilter() + { + try { + $tailors = User::where('role', 'penjahit') + ->withAvg('ratings as average_rating', 'rating') + ->with(['specializations', 'services', 'ratings']) + ->get() + ->map(function ($tailor) { + return [ + 'id' => $tailor->id, + 'name' => $tailor->name, + 'email' => $tailor->email, + 'phone' => $tailor->phone_number, + 'profile' => [ + 'shop_name' => $tailor->name, + 'address' => $tailor->address, + 'description' => $tailor->shop_description, + 'photo' => $tailor->profile_photo, + 'latitude' => $tailor->latitude, + 'longitude' => $tailor->longitude + ], + 'specializations' => $tailor->specializations->map(function ($specialization) { + return [ + 'id' => $specialization->id, + 'name' => $specialization->name, + 'photo' => $specialization->photo + ]; + }), + 'services' => $tailor->services->map(function ($service) { + return [ + 'id' => $service->id, + 'name' => $service->name, + 'price' => $service->price, + 'description' => $service->description, + 'is_available' => $service->is_available + ]; + }), + 'ratings' => [ + 'average_rating' => round($tailor->average_rating ?? 0, 1), + 'total_ratings' => $tailor->ratings->count(), + 'reviews' => $tailor->ratings->map(function ($rating) { + return [ + 'rating' => $rating->rating, + 'comment' => $rating->review, + 'created_at' => $rating->created_at + ]; + }) + ] + ]; + }); + + return response()->json([ + 'status' => 'success', + 'data' => $tailors + ]); + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Failed to retrieve tailors data', + 'error' => $e->getMessage() + ], 500); + } + } + + public function deleteTailor($id) + { + try { + $tailor = User::where('role', 'penjahit')->find($id); + + if (!$tailor) { + return response()->json([ + 'status' => 'error', + 'message' => 'Penjahit tidak ditemukan' + ], 404); + } + + // Hapus relasi spesialisasi terlebih dahulu + $tailor->specializations()->detach(); + + // Hapus relasi gallery + $tailor->gallery()->delete(); + + // Hapus relasi services + $tailor->services()->delete(); + + // Hapus relasi ratings + $tailor->ratings()->delete(); + + // Hapus penjahit + $tailor->delete(); + + return response()->json([ + 'status' => 'success', + 'message' => 'Penjahit berhasil dihapus' + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal menghapus penjahit', + 'error' => $e->getMessage() + ], 500); + } + } + + public function updateTailor(Request $request, $id) + { + try { + // Validasi input + $request->validate([ + 'name' => 'sometimes|string|max:255', + 'email' => 'sometimes|email|unique:users,email,' . $id, + 'phone_number' => 'sometimes|string|max:20', + 'address' => 'sometimes|string', + 'shop_description' => 'sometimes|string', + 'latitude' => 'sometimes|numeric', + 'longitude' => 'sometimes|numeric', + 'specialization_ids' => 'sometimes|array', + 'specialization_ids.*' => 'exists:tailor_specializations,id' + ]); + + // Cari penjahit + $tailor = User::where('role', 'penjahit')->find($id); + + if (!$tailor) { + return response()->json([ + 'status' => 'error', + 'message' => 'Penjahit tidak ditemukan' + ], 404); + } + + // Update data dasar + $tailor->update($request->only([ + 'name', + 'email', + 'phone_number', + 'address', + 'shop_description', + 'latitude', + 'longitude' + ])); + + // Update spesialisasi jika ada + if ($request->has('specialization_ids')) { + $tailor->specializations()->sync($request->specialization_ids); + } + + // Load ulang relasi untuk memastikan data terbaru + $tailor->load('specializations'); + + return response()->json([ + 'status' => 'success', + 'message' => 'Data penjahit berhasil diperbarui', + 'data' => [ + 'id' => $tailor->id, + 'name' => $tailor->name, + 'email' => $tailor->email, + 'phone_number' => $tailor->phone_number, + 'address' => $tailor->address, + 'shop_description' => $tailor->shop_description, + 'profile_photo' => $tailor->profile_photo, + 'location' => [ + 'latitude' => $tailor->latitude, + 'longitude' => $tailor->longitude + ], + 'specializations' => $tailor->specializations->map(function ($spec) { + return [ + 'id' => $spec->id, + 'name' => $spec->name, + 'icon' => $spec->icon + ]; + }) + ] + ]); + + } catch (\Illuminate\Validation\ValidationException $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Validasi gagal', + 'errors' => $e->errors() + ], 422); + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal memperbarui data penjahit', + 'error' => $e->getMessage() + ], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorDashboardController.php b/TA_API/app/Http/Controllers/Api/TailorDashboardController.php new file mode 100644 index 0000000..c05427e --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorDashboardController.php @@ -0,0 +1,62 @@ +where('status', 'pending') + ->with(['customer:id,name', 'customer.ratings']) + ->orderBy('created_at', 'desc') + ->get(); + + // Calculate current month's earnings + $currentMonthEarnings = Booking::where('tailor_id', $tailor_id) + ->where('status', 'selesai') + ->where('payment_status', 'paid') + ->whereYear('updated_at', $now->year) + ->whereMonth('updated_at', $now->month) + ->sum('total_price'); + + // Calculate total earnings + $totalEarnings = Booking::where('tailor_id', $tailor_id) + ->where('status', 'selesai') + ->where('payment_status', 'paid') + ->sum('total_price'); + + // Get average rating + $averageRating = DB::table('tailor_ratings') + ->where('tailor_id', $tailor_id) + ->avg('rating'); + + return $this->sendResponse([ + 'incoming_bookings' => $incomingBookings, + 'current_month_earnings' => $currentMonthEarnings, + 'total_earnings' => $totalEarnings, + 'average_rating' => round($averageRating ?? 0, 1), + 'total_completed_orders' => Booking::where('tailor_id', $tailor_id) + ->where('status', 'selesai') + ->count() + ], 'Data dashboard berhasil diambil'); + + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data dashboard'], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorGalleryController.php b/TA_API/app/Http/Controllers/Api/TailorGalleryController.php new file mode 100644 index 0000000..2ac2905 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorGalleryController.php @@ -0,0 +1,168 @@ +orderBy('created_at', 'desc') + ->get(); + + return $this->sendResponse($gallery, 'Data galeri berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data galeri'], 500); + } + } + + /** + * Store a new gallery item + */ + public function store(Request $request) + { + try { + // Log request data + \Log::info('Attempting to store gallery photo', [ + 'user_id' => Auth::id(), + 'has_file' => $request->hasFile('photo'), + 'all_data' => $request->all() + ]); + + $validator = Validator::make($request->all(), [ + 'photo' => 'required|image|mimes:jpeg,png,jpg|max:2048', + 'title' => 'nullable|string|max:255', + 'description' => 'nullable|string', + 'category' => 'nullable|string|max:100' + ]); + + if ($validator->fails()) { + \Log::warning('Gallery photo validation failed', [ + 'errors' => $validator->errors()->toArray() + ]); + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Upload dan simpan foto + $photo = $request->file('photo'); + + \Log::info('Photo details', [ + 'original_name' => $photo->getClientOriginalName(), + 'mime_type' => $photo->getMimeType(), + 'size' => $photo->getSize() + ]); + + $fileName = 'gallery_' . time() . '_' . Auth::id() . '.' . $photo->getClientOriginalExtension(); + + try { + $photo->storeAs('gallery_photos', $fileName, 'public'); + \Log::info('Photo stored successfully', ['filename' => $fileName]); + } catch (\Exception $e) { + \Log::error('Failed to store photo', [ + 'error' => $e->getMessage(), + 'filename' => $fileName + ]); + throw $e; + } + + // Buat record galeri baru + $gallery = TailorGallery::create([ + 'user_id' => Auth::id(), + 'photo' => '/storage/gallery_photos/' . $fileName, + 'title' => $request->title, + 'description' => $request->description, + 'category' => $request->category + ]); + + \Log::info('Gallery record created successfully', ['gallery_id' => $gallery->id]); + + return $this->sendResponse($gallery, 'Foto berhasil ditambahkan ke galeri'); + } catch (\Exception $e) { + \Log::error('Error storing gallery photo', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menambah foto: ' . $e->getMessage()], 500); + } + } + + /** + * Update gallery item details + */ + public function update(Request $request, TailorGallery $gallery) + { + try { + // Check ownership + if ($gallery->user_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengubah foto ini'], 403); + } + + $validator = Validator::make($request->all(), [ + 'title' => 'nullable|string|max:255', + 'description' => 'nullable|string', + 'category' => 'nullable|string|max:100' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + $gallery->update($request->only(['title', 'description', 'category'])); + + return $this->sendResponse($gallery, 'Data galeri berhasil diupdate'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate data'], 500); + } + } + + /** + * Delete gallery item + */ + public function destroy(TailorGallery $gallery) + { + try { + // Check ownership + if ($gallery->user_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk menghapus foto ini'], 403); + } + + // Delete photo file + $photoPath = str_replace('/storage/', '', $gallery->photo); + if (Storage::disk('public')->exists($photoPath)) { + Storage::disk('public')->delete($photoPath); + } + + $gallery->delete(); + + return $this->sendResponse(null, 'Foto berhasil dihapus dari galeri'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menghapus foto'], 500); + } + } + + /** + * Get gallery items for a specific tailor (public) + */ + public function getTailorGallery($tailorId) + { + try { + $gallery = TailorGallery::where('user_id', $tailorId) + ->orderBy('created_at', 'desc') + ->get(); + + return $this->sendResponse($gallery, 'Data galeri penjahit berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data galeri'], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorProfileController.php b/TA_API/app/Http/Controllers/Api/TailorProfileController.php new file mode 100644 index 0000000..978b131 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorProfileController.php @@ -0,0 +1,121 @@ +load('specializations'); + + return $this->sendResponse([ + 'id' => $user->id, + 'name' => $user->name, + 'phone_number' => $user->phone_number, + 'address' => $user->address, + 'shop_description' => $user->shop_description, + 'profile_photo' => $user->profile_photo ? asset('storage/' . $user->profile_photo) : null, + 'specializations' => $user->specializations->map(function($spec) { + return [ + 'id' => $spec->id, + 'name' => $spec->name + ]; + }) + ], 'Data profil toko berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data profil'], 500); + } + } + + /** + * Update tailor shop profile + */ + public function updateProfile(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'phone_number' => 'required|string|max:15', + 'address' => 'required|string|max:500', + 'shop_description' => 'nullable|string|max:1000', + 'profile_photo' => 'nullable|image|mimes:jpeg,png,jpg|max:2048' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + $user = Auth::user(); + + // Handle profile photo upload + if ($request->hasFile('profile_photo')) { + // Delete old photo if exists + if ($user->profile_photo) { + Storage::disk('public')->delete($user->profile_photo); + } + + // Store new photo + $path = $request->file('profile_photo')->store('profile_photos', 'public'); + $user->profile_photo = $path; + } + + // Update user data + $user->name = $request->name; + $user->phone_number = $request->phone_number; + $user->address = $request->address; + $user->shop_description = $request->shop_description; + $user->save(); + + // Reload user with specializations + $user->load('specializations'); + + return $this->sendResponse([ + 'id' => $user->id, + 'name' => $user->name, + 'phone_number' => $user->phone_number, + 'address' => $user->address, + 'shop_description' => $user->shop_description, + 'profile_photo' => $user->profile_photo ? asset('storage/' . $user->profile_photo) : null, + 'specializations' => $user->specializations->map(function($spec) { + return [ + 'id' => $spec->id, + 'name' => $spec->name + ]; + }) + ], 'Profil toko berhasil diupdate'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate profil'], 500); + } + } + + /** + * Delete profile photo + */ + public function deleteProfilePhoto() + { + try { + $user = Auth::user(); + + if ($user->profile_photo) { + Storage::disk('public')->delete($user->profile_photo); + $user->profile_photo = null; + $user->save(); + } + + return $this->sendResponse(null, 'Foto profil berhasil dihapus'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menghapus foto profil'], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorSearchController.php b/TA_API/app/Http/Controllers/Api/TailorSearchController.php new file mode 100644 index 0000000..16a3814 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorSearchController.php @@ -0,0 +1,483 @@ +with('specializations'); + + // Filter by specialization if provided + if ($request->has('specialization_id') && $request->specialization_id) { + $query->whereHas('specializations', function ($q) use ($request) { + $q->where('tailor_specializations.id', $request->specialization_id); + }); + } + + // Get user's current peminatan if logged in as customer + $userPreferred = []; + $user = Auth::user(); + if ($user && $user->role === 'pelanggan') { + $userPreferred = $user->preferredSpecializations->pluck('id')->toArray(); + } + + // Get tailors + $tailors = $query->get(); + + // Add distance if customer has coordinates + if ($user && $user->role === 'pelanggan' && $user->latitude && $user->longitude) { + foreach ($tailors as $tailor) { + if ($tailor->latitude && $tailor->longitude) { + $tailor->distance = $this->calculateDistance( + $user->latitude, + $user->longitude, + $tailor->latitude, + $tailor->longitude + ); + } else { + $tailor->distance = null; + } + } + + // Sort by distance if available + $tailors = $tailors->sortBy('distance'); + } + + return $this->sendResponse([ + 'tailors' => $tailors->values(), + 'user_preferred' => $userPreferred + ], 'Data penjahit berhasil diambil'); + + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mencari penjahit: ' . $e->getMessage()], 500); + } + } + + /** + * Get recommended tailors based on customer preferences using Content-Based Filtering + */ + public function getRecommended() + { + try { + // Log untuk debug + \Log::info('Accessing getRecommended method'); + + $user = Auth::user(); + + // Check if user is customer + if (!$user || $user->role !== 'pelanggan') { + \Log::warning('User not authorized: ', ['user' => $user ? $user->toArray() : 'null']); + return $this->sendError('Unauthorized.', ['error' => 'Anda harus login sebagai pelanggan'], 403); + } + + // Get user's preferred specializations + $preferredSpecIds = $user->preferredSpecializations->pluck('id')->toArray(); + \Log::info('User preferred specializations: ', ['preferred' => $preferredSpecIds]); + + // Get all available specializations for feature vector preparation + $allSpecializations = TailorSpecialization::all()->pluck('id')->toArray(); + + // Get all tailors + $allTailors = User::where('role', 'penjahit') + ->with(['specializations', 'ratings']) + ->get(); + + if (empty($preferredSpecIds)) { + // If no preferences, return popular tailors + \Log::info('No preferences found, returning popular tailors'); + $tailors = User::where('role', 'penjahit') + ->withCount([ + 'bookings' => function ($query) { + $query->where('status', 'selesai'); + } + ]) + ->orderBy('bookings_count', 'desc') + ->with(['specializations', 'ratings']) + ->limit(10) + ->get(); + } else { + + // Mengubah preferensi user menjadi vektor + $userProfile = $this->createFeatureVector($preferredSpecIds, $allSpecializations); + + // Calculate similarity scores for all tailors + $tailorsWithScores = []; + foreach ($allTailors as $tailor) { + $tailorSpecIds = $tailor->specializations->pluck('id')->toArray(); + $tailorProfile = $this->createFeatureVector($tailorSpecIds, $allSpecializations); + + // Calculate cosine similarity between user and tailor profiles + $similarityScore = $this->calculateCosineSimilarity($userProfile, $tailorProfile); + + // Only include tailors with some similarity + if ($similarityScore > 0) { + $tailor->similarity_score = $similarityScore; + $tailorsWithScores[] = $tailor; + } + } + + // Sort tailors by similarity score + $tailors = collect($tailorsWithScores)->sortByDesc('similarity_score'); + + // If no similar tailors found, return popular ones + if ($tailors->isEmpty()) { + $tailors = User::where('role', 'penjahit') + ->withCount([ + 'bookings' => function ($query) { + $query->where('status', 'selesai'); + } + ]) + ->orderBy('bookings_count', 'desc') + ->with(['specializations', 'ratings']) + ->limit(10) + ->get(); + } + } + + \Log::info('Tailors found: ', ['count' => $tailors->count()]); + + // Add distance and rating information + foreach ($tailors as $tailor) { + // Calculate distance if coordinates available + if ($user->latitude && $user->longitude && $tailor->latitude && $tailor->longitude) { + $tailor->distance = $this->calculateDistance( + $user->latitude, + $user->longitude, + $tailor->latitude, + $tailor->longitude + ); + } else { + $tailor->distance = null; + } + + // Calculate average rating + $ratings = $tailor->ratings; + if ($ratings->count() > 0) { + $tailor->rating_info = [ + 'average_rating' => round($ratings->avg('rating'), 1), + 'total_reviews' => $ratings->count(), + 'reviews' => $ratings->map(function ($rating) { + return [ + 'rating' => $rating->rating, + 'review' => $rating->review, + 'created_at' => $rating->created_at, + 'customer' => [ + 'id' => $rating->customer->id, + 'name' => $rating->customer->name, + 'profile_photo' => $rating->customer->profile_photo + ] + ]; + }) + ]; + } else { + $tailor->rating_info = [ + 'average_rating' => 0, + 'total_reviews' => 0, + 'reviews' => [] + ]; + } + } + + // If user has location, use hybrid approach combining similarity and distance + if ($user->latitude && $user->longitude) { + // Normalize scores for hybrid ranking + $maxDistance = $tailors->max('distance') ?: 1; + $tailors = $tailors->map(function ($tailor) use ($maxDistance) { + // Calculate normalized distance score (1 when closest, 0 when furthest) + if ($tailor->distance !== null) { + $tailor->distance_score = 1 - ($tailor->distance / $maxDistance); + } else { + $tailor->distance_score = 0; + } + + // Hybrid score (70% similarity, 30% proximity) + $tailor->hybrid_score = isset($tailor->similarity_score) + ? ($tailor->similarity_score * 0.7) + ($tailor->distance_score * 0.3) + : $tailor->distance_score; + + return $tailor; + })->sortByDesc('hybrid_score'); + } + + return $this->sendResponse([ + 'tailors' => $tailors->values(), + 'user_preferred' => $preferredSpecIds + ], 'Rekomendasi penjahit berhasil diambil'); + + } catch (\Exception $e) { + \Log::error('Content-Based Filtering error: ' . $e->getMessage() . "\n" . $e->getTraceAsString()); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mendapatkan rekomendasi: ' . $e->getMessage()], 500); + } + } + + /** + * Create binary feature vector based on specializations + */ + private function createFeatureVector($specializations, $allSpecializations) + { + $vector = []; + foreach ($allSpecializations as $specId) { + $vector[$specId] = in_array($specId, $specializations) ? 1 : 0; + } + return $vector; + } + + /** + * Calculate cosine similarity between two feature vectors + */ + private function calculateCosineSimilarity($vectorA, $vectorB) + { + $dotProduct = 0; + $magnitudeA = 0; + $magnitudeB = 0; + + foreach ($vectorA as $key => $valueA) { + $valueB = $vectorB[$key] ?? 0; + + $dotProduct += $valueA * $valueB; + $magnitudeA += $valueA * $valueA; + $magnitudeB += $valueB * $valueB; + } + + $magnitudeA = sqrt($magnitudeA); + $magnitudeB = sqrt($magnitudeB); + + if ($magnitudeA == 0 || $magnitudeB == 0) { + return 0; + } + + return $dotProduct / ($magnitudeA * $magnitudeB); + } + + + /** + * Get dashboard data including nearby and recommended tailors + */ + public function getDashboardData(Request $request) + { + try { + $user = Auth::user();//Periksa apakah user yang login adalah pelanggan? + if (!$user || !$user->isPelanggan()) { + return $this->sendError('Unauthorized.', [], 401); + } + + // Get nearby tailors- Mendapatkan Penjahit terdekat + $nearbyTailors = User::where('role', 'penjahit') + ->whereNotNull('latitude') + ->whereNotNull('longitude') + ->with(['specializations', 'services']) + ->get() + ->map(function ($tailor) use ($user) { + if ($user->latitude && $user->longitude && $tailor->latitude && $tailor->longitude) { + $tailor->distance = $this->calculateDistance( + $user->latitude, + $user->longitude, + $tailor->latitude, + $tailor->longitude + ); + } else { + $tailor->distance = null; + } + return $tailor; + }) + ->sortBy('distance') + ->take(5); + + // Get recommended tailors based on user's preferences + $preferredSpecIds = $user->preferredSpecializations() + ->select('tailor_specializations.id') + ->pluck('tailor_specializations.id') + ->toArray(); + + $recommendedTailors = collect([]); + if (!empty($preferredSpecIds)) { + $recommendedTailors = User::where('role', 'penjahit') + ->with(['specializations', 'services']) + ->whereHas('specializations', function ($query) use ($preferredSpecIds) { + $query->whereIn('tailor_specializations.id', $preferredSpecIds); + }) + ->withCount(['bookings' => function ($query) { + $query->where('status', 'selesai'); + }]) + ->orderBy('bookings_count', 'desc') + ->take(5) + ->get() + ->map(function ($tailor) use ($user) { + if ($user->latitude && $user->longitude && $tailor->latitude && $tailor->longitude) { + $tailor->distance = $this->calculateDistance( + $user->latitude, + $user->longitude, + $tailor->latitude, + $tailor->longitude + ); + } else { + $tailor->distance = null; + } + return $tailor; + }); + } + + return $this->sendResponse([ + 'nearby_tailors' => $nearbyTailors->values(), + 'recommended_tailors' => $recommendedTailors->values(), + 'user_preferences' => $user->preferredSpecializations + ], 'Dashboard data retrieved successfully.'); + + } catch (\Exception $e) { + \Log::error('Dashboard error: ' . $e->getMessage()); + return $this->sendError('Error retrieving dashboard data.', ['error' => $e->getMessage()], 500); + } + } + + /** + * Calculate distance between two points in kilometers + * Fungsi untuk perhitungan Jarak untuk mencari penjahit Terdekat + */ + private function calculateDistance($lat1, $lon1, $lat2, $lon2) + { + $earthRadius = 6371; // Jari-jari bumi dalam kilometer + + $latDelta = deg2rad($lat2 - $lat1); + $lonDelta = deg2rad($lon2 - $lon1); + + $a = sin($latDelta / 2) * sin($latDelta / 2) + + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * + sin($lonDelta / 2) * sin($lonDelta / 2); + + $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); + + return round($earthRadius * $c, 2); + } + + /** + * Get detailed information about a tailor + */ + public function getTailorDetail($id) + { + try { + // Log untuk debug + \Log::info('Accessing getTailorDetail method', ['id' => $id]); + + $tailor = User::where('id', $id) + ->where('role', 'penjahit') + ->with([ + 'specializations', + 'services' => function($query) { + $query->where('is_available', true); + }, + 'gallery' + ]) + ->withCount([ + 'bookings as completed_orders' => function($query) { + $query->where('status', 'selesai'); + } + ]) + ->first(); + + \Log::info('Tailor query result:', ['tailor' => $tailor ? 'found' : 'not found']); + + if (!$tailor) { + return $this->sendError('Not found.', ['error' => 'Penjahit tidak ditemukan'], 404); + } + + // Get average rating + $avgRating = DB::table('tailor_ratings') + ->where('tailor_id', $id) + ->avg('rating'); + + $tailor->average_rating = round($avgRating ?? 0, 1); + + // Calculate distance if user is logged in and has coordinates + $user = Auth::user(); + if ($user && $user->role === 'pelanggan' && $user->latitude && $user->longitude && $tailor->latitude && $tailor->longitude) { + $tailor->distance = $this->calculateDistance( + $user->latitude, + $user->longitude, + $tailor->latitude, + $tailor->longitude + ); + } else { + $tailor->distance = null; + } + + // Get gallery photos + $gallery = \App\Models\TailorGallery::where('user_id', $id) + ->orderBy('created_at', 'desc') + ->get(); + + // Prepare response data + $responseData = $tailor->toArray(); + $responseData['gallery'] = $gallery; + + return $this->sendResponse($responseData, 'Detail penjahit berhasil diambil'); + + } catch (\Exception $e) { + \Log::error('Error in getTailorDetail', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil detail penjahit: ' . $e->getMessage()], 500); + } + } + + /** + * Search tailors by name + * + * @param string $name + * @return \Illuminate\Http\Response + */ + public function searchByName($name) + { + try { + if (!$name) { + return $this->sendError('Error.', ['error' => 'Parameter nama diperlukan'], 400); + } + + $query = User::where('role', 'penjahit') + ->where('name', 'LIKE', "%{$name}%") + ->with('specializations'); + + // Get tailors + $tailors = $query->get(); + + // Add distance if customer is logged in and has coordinates + $user = Auth::user(); + if ($user && $user->role === 'pelanggan' && $user->latitude && $user->longitude) { + foreach ($tailors as $tailor) { + if ($tailor->latitude && $tailor->longitude) { + $tailor->distance = $this->calculateDistance( + $user->latitude, + $user->longitude, + $tailor->latitude, + $tailor->longitude + ); + } else { + $tailor->distance = null; + } + } + + // Sort by distance if available + $tailors = $tailors->sortBy('distance'); + } + + return $this->sendResponse([ + 'tailors' => $tailors->values() + ], 'Data penjahit berhasil diambil'); + + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mencari penjahit: ' . $e->getMessage()], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorServiceController.php b/TA_API/app/Http/Controllers/Api/TailorServiceController.php new file mode 100644 index 0000000..5270a32 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorServiceController.php @@ -0,0 +1,183 @@ +orderBy('created_at', 'desc') + ->get(); + + return $this->sendResponse($services, 'Data jasa berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data jasa'], 500); + } + } + + /** + * Store a new service + */ + public function store(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'description' => 'required|string|max:1000', + 'price' => 'required|numeric|min:0', + 'category' => 'required|string|in:Bawahan,Atasan,Terusan,Perbaikan', + 'estimated_days' => 'required|integer|min:1', + 'service_photo' => 'nullable|image|mimes:jpeg,png,jpg|max:2048' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + $serviceData = $request->only([ + 'name', + 'description', + 'price', + 'category', + 'estimated_days' + ]); + + $serviceData['user_id'] = Auth::id(); + + // Handle service photo upload + if ($request->hasFile('service_photo')) { + $path = $request->file('service_photo')->store('service_photos', 'public'); + $serviceData['service_photo'] = $path; + } + + $service = TailorService::create($serviceData); + + return $this->sendResponse($service, 'Jasa berhasil ditambahkan'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menambahkan jasa'], 500); + } + } + + /** + * Update the specified service + */ + public function update(Request $request, TailorService $service) + { + try { + // Check if the service belongs to the authenticated tailor + if ($service->user_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengubah jasa ini'], 403); + } + + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'description' => 'required|string|max:1000', + 'price' => 'required|numeric|min:0', + 'category' => 'required|string|in:Bawahan,Atasan,Terusan,Perbaikan', + 'estimated_days' => 'required|integer|min:1', + 'is_available' => 'required|boolean', + 'service_photo' => 'nullable|image|mimes:jpeg,png,jpg|max:2048' + ]); + + if ($validator->fails()) { + return $this->sendError('Error validasi.', $validator->errors(), 422); + } + + // Handle service photo upload + if ($request->hasFile('service_photo')) { + // Delete old photo if exists + if ($service->service_photo) { + Storage::disk('public')->delete($service->service_photo); + } + + $path = $request->file('service_photo')->store('service_photos', 'public'); + $service->service_photo = $path; + } + + $service->update($request->only([ + 'name', + 'description', + 'price', + 'category', + 'estimated_days', + 'is_available' + ])); + + return $this->sendResponse($service, 'Jasa berhasil diupdate'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengupdate jasa'], 500); + } + } + + /** + * Delete the specified service + */ + public function destroy(TailorService $service) + { + try { + // Check if the service belongs to the authenticated tailor + if ($service->user_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk menghapus jasa ini'], 403); + } + + // Delete service photo if exists + if ($service->service_photo) { + Storage::disk('public')->delete($service->service_photo); + } + + $service->delete(); + + return $this->sendResponse(null, 'Jasa berhasil dihapus'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat menghapus jasa'], 500); + } + } + + /** + * Toggle service availability + */ + public function toggleAvailability(TailorService $service) + { + try { + // Check if the service belongs to the authenticated tailor + if ($service->user_id !== Auth::id()) { + return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk mengubah status jasa ini'], 403); + } + + $service->is_available = !$service->is_available; + $service->save(); + + return $this->sendResponse($service, 'Status ketersediaan jasa berhasil diubah'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengubah status jasa'], 500); + } + } + + /** + * Get services by tailor ID (public) + */ + public function getTailorServices($tailorId) + { + try { + $services = TailorService::where('user_id', $tailorId) + ->where('is_available', true) + ->orderBy('created_at', 'desc') + ->get(); + + return $this->sendResponse($services, 'Data jasa penjahit berhasil diambil'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat mengambil data jasa'], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/TailorSpecializationController.php b/TA_API/app/Http/Controllers/Api/TailorSpecializationController.php new file mode 100644 index 0000000..01e290b --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/TailorSpecializationController.php @@ -0,0 +1,416 @@ +json([ + 'status' => 'success', + 'data' => $specializations + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal mengambil data spesialisasi', + 'error' => $e->getMessage() + ], 500); + } + } + + public function store(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'category' => 'required|string|max:255', + 'icon' => 'nullable|string', + 'photo' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048' + ]); + + if ($validator->fails()) { + \Log::error('Validation failed', ['errors' => $validator->errors()]); + return response()->json([ + 'status' => 'error', + 'message' => $validator->errors() + ], 422); + } + + $specialization = new TailorSpecialization(); + $specialization->name = $request->name; + $specialization->category = $request->category; + $specialization->icon = $request->icon; + $specialization->save(); + + if ($request->hasFile('photo')) { + try { + $photo = $request->file('photo'); + + \Log::info('Photo file information', [ + 'original_name' => $photo->getClientOriginalName(), + 'mime_type' => $photo->getMimeType(), + 'size' => $photo->getSize(), + 'error' => $photo->getError() + ]); + + if (!$photo->isValid()) { + throw new \Exception('Invalid file upload: ' . $photo->getErrorMessage()); + } + + // Simpan file menggunakan putFileAs + $filename = 'specialization_' . time() . '_' . $specialization->id . '.' . $photo->getClientOriginalExtension(); + + // Pastikan direktori exists + $path = storage_path('app/public/specialization_photos'); + if (!file_exists($path)) { + mkdir($path, 0755, true); + } + + // Simpan file menggunakan move + $photo->move($path, $filename); + + // Verifikasi file exists + if (!file_exists($path . '/' . $filename)) { + throw new \Exception('File not found after moving'); + } + + $specialization->photo = '/storage/specialization_photos/' . $filename; + $specialization->save(); + + \Log::info('File saved successfully', [ + 'path' => $path . '/' . $filename, + 'exists' => file_exists($path . '/' . $filename), + 'url' => $specialization->photo + ]); + + } catch (\Exception $e) { + \Log::error('Error handling photo upload', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + throw new \Exception('Error handling photo: ' . $e->getMessage()); + } + } + + return response()->json([ + 'status' => 'success', + 'message' => 'Spesialisasi berhasil ditambahkan', + 'data' => $specialization + ], 201); + + } catch (\Exception $e) { + \Log::error('Error in store method', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return response()->json([ + 'status' => 'error', + 'message' => 'Terjadi kesalahan saat menambahkan spesialisasi: ' . $e->getMessage() + ], 500); + } + } + + public function show($id) + { + try { + $specialization = TailorSpecialization::findOrFail($id); + + return response()->json([ + 'status' => 'success', + 'data' => $specialization + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Spesialisasi tidak ditemukan', + 'error' => $e->getMessage() + ], 404); + } + } + + public function update(Request $request, $id) + { + try { + \Log::info('Update request received', [ + 'id' => $id, + 'request_data' => $request->all(), + 'has_file' => $request->hasFile('photo'), + 'content_type' => $request->header('Content-Type'), + 'files' => $_FILES, // Log PHP's native FILES array + 'method' => $request->method() + ]); + + // Alternate way to get form data for PUT requests + $input = []; + if ($request->isMethod('put') && empty($request->all())) { + // Try to get data from PHP's input directly for PUT + parse_str(file_get_contents("php://input"), $putData); + \Log::info('PUT data parsed', ['put_data' => $putData]); + + // Basic fields + $input['name'] = $putData['name'] ?? null; + $input['category'] = $putData['category'] ?? null; + $input['icon'] = $putData['icon'] ?? null; + + // Use native FILES for the photo + if (!empty($_FILES['photo']['name'])) { + $input['photo'] = $_FILES['photo']; + } + } else { + $input = $request->all(); + } + + // Debug untuk memastikan data diterima dengan benar + \Log::info('Input data', [ + 'input' => $input, + 'name_exists' => isset($input['name']), + 'category_exists' => isset($input['category']), + ]); + + $validator = Validator::make($input, [ + 'name' => 'required|string|max:255', + 'category' => 'required|string|max:255', + 'icon' => 'nullable|string', + 'photo' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048' + ]); + + if ($validator->fails()) { + \Log::error('Validation failed', [ + 'errors' => $validator->errors() + ]); + return response()->json([ + 'status' => 'error', + 'message' => 'Validasi gagal', + 'errors' => $validator->errors() + ], 422); + } + + $specialization = TailorSpecialization::findOrFail($id); + \Log::info('Current specialization data', [ + 'before_update' => $specialization->toArray() + ]); + + // Update basic fields + $specialization->name = $input['name']; + $specialization->category = $input['category']; + $specialization->icon = $input['icon'] ?? null; + + if ($request->hasFile('photo')) { + \Log::info('Processing photo upload'); + // Delete old photo if exists + if ($specialization->photo) { + $oldPhotoPath = str_replace('/storage/', '', $specialization->photo); + if (Storage::disk('public')->exists($oldPhotoPath)) { + Storage::disk('public')->delete($oldPhotoPath); + \Log::info('Old photo deleted', ['path' => $oldPhotoPath]); + } + } + + $photo = $request->file('photo'); + $filename = 'specialization_' . time() . '_' . $id . '.' . $photo->getClientOriginalExtension(); + + // Pastikan direktori exists + $path = storage_path('app/public/specialization_photos'); + if (!file_exists($path)) { + mkdir($path, 0755, true); + } + + // Simpan file menggunakan move + $photo->move($path, $filename); + + $specialization->photo = '/storage/specialization_photos/' . $filename; + \Log::info('New photo saved', ['path' => $specialization->photo]); + } + + $specialization->save(); + + // Force refresh from database + $specialization = TailorSpecialization::findOrFail($id); + + \Log::info('Specialization updated successfully', [ + 'after_update' => $specialization->toArray() + ]); + + return response()->json([ + 'status' => 'success', + 'message' => 'Spesialisasi berhasil diperbarui', + 'data' => $specialization + ]); + + } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) { + \Log::error('Specialization not found', ['id' => $id]); + return response()->json([ + 'status' => 'error', + 'message' => 'Spesialisasi tidak ditemukan' + ], 404); + } catch (\Exception $e) { + \Log::error('Update failed', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal memperbarui spesialisasi', + 'error' => $e->getMessage() + ], 500); + } + } + + public function destroy($id) + { + try { + $specialization = TailorSpecialization::findOrFail($id); + + // Hapus foto jika ada + if ($specialization->photo) { + $photoPath = str_replace('/storage/', '', $specialization->photo); + if (Storage::disk('public')->exists($photoPath)) { + Storage::disk('public')->delete($photoPath); + } + } + + // Hapus spesialisasi + $specialization->delete(); + + return response()->json([ + 'status' => 'success', + 'message' => 'Spesialisasi berhasil dihapus' + ]); + + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal menghapus spesialisasi', + 'error' => $e->getMessage() + ], 500); + } + } + + /** + * Get all specializations with photos grouped by category + */ + public function getAllSpecializations() + { + try { + $specializations = TailorSpecialization::all() + ->groupBy('category') + ->map(function ($items) { + return $items->map(function ($item) { + return [ + 'id' => $item->id, + 'name' => $item->name, + 'photo' => $item->photo, + 'category' => $item->category + ]; + }); + }); + + return response()->json([ + 'status' => 'success', + 'message' => 'Data spesialisasi berhasil diambil', + 'data' => $specializations + ]); + } catch (\Exception $e) { + return response()->json([ + 'status' => 'error', + 'message' => 'Terjadi kesalahan saat mengambil data spesialisasi', + 'error' => $e->getMessage() + ], 500); + } + } + + /** + * Update foto spesialisasi + */ + public function updatePhoto(Request $request, $id) + { + try { + \Log::info('User attempting to update photo', [ + 'user' => auth()->user(), + 'id' => $id + ]); + + if (!auth()->user()->isAdmin()) { + \Log::warning('Unauthorized access attempt', [ + 'user' => auth()->user(), + 'role' => auth()->user()->role + ]); + return response()->json([ + 'status' => 'error', + 'message' => 'Unauthorized', + 'error' => 'Only admin can update specialization photos' + ], 403); + } + + $validator = Validator::make($request->all(), [ + 'photo' => 'required|image|mimes:jpeg,png,jpg|max:2048' + ]); + + if ($validator->fails()) { + \Log::error('Validation failed', [ + 'errors' => $validator->errors() + ]); + return response()->json([ + 'status' => 'error', + 'message' => 'Error validasi', + 'errors' => $validator->errors() + ], 422); + } + + $specialization = TailorSpecialization::findOrFail($id); + + // Hapus foto lama jika ada + if ($specialization->photo) { + $oldPhotoPath = str_replace('/storage/', '', $specialization->photo); + if (Storage::disk('public')->exists($oldPhotoPath)) { + Storage::disk('public')->delete($oldPhotoPath); + } + } + + // Upload dan simpan foto baru + $photo = $request->file('photo'); + $fileName = 'specialization_' . time() . '_' . $id . '.' . $photo->getClientOriginalExtension(); + $photo->storeAs('specialization_photos', $fileName, 'public'); + + // Update path foto di database + $specialization->photo = '/storage/specialization_photos/' . $fileName; + $specialization->save(); + + \Log::info('Photo updated successfully', [ + 'specialization_id' => $id, + 'file_name' => $fileName + ]); + + return response()->json([ + 'status' => 'success', + 'message' => 'Foto spesialisasi berhasil diupdate', + 'data' => [ + 'photo' => $specialization->photo + ] + ]); + + } catch (\Exception $e) { + \Log::error('Error updating photo', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return response()->json([ + 'status' => 'error', + 'message' => 'Error update foto', + 'error' => $e->getMessage() + ], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/Api/WalletController.php b/TA_API/app/Http/Controllers/Api/WalletController.php new file mode 100644 index 0000000..df48853 --- /dev/null +++ b/TA_API/app/Http/Controllers/Api/WalletController.php @@ -0,0 +1,164 @@ +wallet; + if (!$wallet) { + $wallet = Wallet::create([ + 'user_id' => Auth::id(), + 'balance' => 0 + ]); + } + + // Menghitung total pending withdrawals + $pendingWithdrawals = Withdrawal::where('wallet_id', $wallet->id) + ->whereIn('status', ['pending', 'processing']) + ->sum('amount'); + + // Menghitung saldo yang tersedia + $availableBalance = $wallet->balance - $pendingWithdrawals; + + return $this->sendResponse([ + 'balance' => $wallet->balance, + 'pending_withdrawals' => $pendingWithdrawals, + 'available_balance' => $availableBalance, + 'transactions' => $wallet->transactions()->with('booking')->latest()->get() + ], 'Wallet information retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function registerBankAccount(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'bank_name' => 'required|string', + 'account_number' => 'required|string', + 'account_holder_name' => 'required|string' + ]); + + if ($validator->fails()) { + return $this->sendError('Validation Error.', $validator->errors(), 422); + } + + $bankAccount = BankAccount::create([ + 'user_id' => Auth::id(), + 'bank_name' => $request->bank_name, + 'account_number' => $request->account_number, + 'account_holder_name' => $request->account_holder_name, + 'status' => 'pending' + ]); + + return $this->sendResponse($bankAccount, 'Bank account registered successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function requestWithdrawal(Request $request) + { + try { + $validator = Validator::make($request->all(), [ + 'bank_account_id' => 'required|exists:bank_accounts,id', + 'amount' => 'required|numeric|min:10000' + ]); + + if ($validator->fails()) { + return $this->sendError('Validation Error.', $validator->errors(), 422); + } + + $wallet = Auth::user()->wallet; + if (!$wallet) { + return $this->sendError('Wallet not found.', [], 404); + } + + // Validasi saldo yang tersedia + if ($wallet->balance < $request->amount) { + return $this->sendError('Insufficient balance.', [ + 'balance' => $wallet->balance, + 'requested_amount' => $request->amount + ], 422); + } + + $bankAccount = BankAccount::find($request->bank_account_id); + if ($bankAccount->status !== 'active') { + return $this->sendError('Invalid bank account.', [], 422); + } + + // Kurangi saldo wallet + $wallet->deductBalance( + $request->amount, + 'Withdrawal request #' . time() + ); + + $withdrawal = Withdrawal::create([ + 'wallet_id' => $wallet->id, + 'bank_account_id' => $bankAccount->id, + 'amount' => $request->amount, + 'status' => 'pending' + ]); + + return $this->sendResponse([ + 'withdrawal' => $withdrawal, + 'wallet' => [ + 'balance' => $wallet->balance, + 'pending_withdrawals' => $request->amount, + 'available_balance' => $wallet->balance + ] + ], 'Withdrawal request submitted successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function getWithdrawalHistory(Request $request) + { + try { + $wallet = Auth::user()->wallet; + if (!$wallet) { + return $this->sendResponse([], 'No withdrawal history found'); + } + + $query = $wallet->withdrawals()->with('bankAccount'); + + // Filter berdasarkan status jika parameter status ada + if ($request->has('status') && in_array($request->status, ['pending', 'processing', 'completed', 'rejected'])) { + $query->where('status', $request->status); + } + + $withdrawals = $query->latest()->get(); + + return $this->sendResponse($withdrawals, 'Withdrawal history retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } + + public function getBankAccounts() + { + try { + $bankAccounts = Auth::user()->bankAccounts() + ->orderBy('created_at', 'desc') + ->get(); + + return $this->sendResponse($bankAccounts, 'Bank accounts retrieved successfully'); + } catch (\Exception $e) { + return $this->sendError('Error.', ['error' => $e->getMessage()], 500); + } + } +} diff --git a/TA_API/app/Http/Controllers/BookingController.php b/TA_API/app/Http/Controllers/BookingController.php new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/TA_API/app/Http/Controllers/BookingController.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/TA_API/app/Http/Controllers/Controller.php b/TA_API/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..8677cd5 --- /dev/null +++ b/TA_API/app/Http/Controllers/Controller.php @@ -0,0 +1,8 @@ +exists($path)) { + abort(404, 'File tidak ditemukan'); + } + + // Dapatkan path fisik file + $filePath = Storage::disk('public')->path($path); + + // Set tipe konten berdasarkan ekstensi file + $contentType = $this->getContentType($filePath); + + // Pastikan file bisa dibaca + if (!File::isReadable($filePath)) { + abort(403, 'Tidak dapat membaca file'); + } + + // Return file response dengan header yang tepat + return response()->file($filePath, [ + 'Content-Type' => $contentType, + 'Cache-Control' => 'public, max-age=86400', + 'Access-Control-Allow-Origin' => '*', + 'X-Content-Type-Options' => 'nosniff' + ]); + } + + /** + * Menampilkan file dari subdirektori tertentu + * + * @param string $directory + * @param string $filename + * @return BinaryFileResponse + */ + public function serveDirectoryFile($directory, $filename) + { + return $this->serveFile("$directory/$filename"); + } + + /** + * Mendapatkan tipe konten berdasarkan ekstensi file + * + * @param string $filePath + * @return string + */ + private function getContentType($filePath) + { + $extension = pathinfo($filePath, PATHINFO_EXTENSION); + + $contentTypes = [ + 'png' => 'image/png', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'gif' => 'image/gif', + 'svg' => 'image/svg+xml', + 'pdf' => 'application/pdf', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'zip' => 'application/zip', + 'mp4' => 'video/mp4', + 'mp3' => 'audio/mpeg', + ]; + + return $contentTypes[strtolower($extension)] ?? 'application/octet-stream'; + } +} diff --git a/TA_API/app/Http/Kernel.php b/TA_API/app/Http/Kernel.php new file mode 100644 index 0000000..c3977f2 --- /dev/null +++ b/TA_API/app/Http/Kernel.php @@ -0,0 +1,57 @@ + + */ + protected $middleware = [ + // + \App\Http\Middleware\CorsMiddleware::class, + ]; + + /** + * The application's route middleware groups. + * + * @var array> + */ + protected $middlewareGroups = [ + 'web' => [ + // Web middleware group + ], + + 'api' => [ + // API middleware group + ], + ]; + + /** + * The application's route middleware aliases. + * + * Aliases may be used instead of class names to assign middleware to routes and groups. + * + * @var array + */ + protected $middlewareAliases = [ + 'auth' => \App\Http\Middleware\Authenticate::class, + 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, + 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, + 'can' => \Illuminate\Auth\Middleware\Authorize::class, + 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, + 'signed' => \App\Http\Middleware\ValidateSignature::class, + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, + 'role' => \App\Http\Middleware\CheckRole::class, + 'cors' => \App\Http\Middleware\CorsMiddleware::class, + ]; +} \ No newline at end of file diff --git a/TA_API/app/Http/Middleware/CheckRole.php b/TA_API/app/Http/Middleware/CheckRole.php new file mode 100644 index 0000000..0a58783 --- /dev/null +++ b/TA_API/app/Http/Middleware/CheckRole.php @@ -0,0 +1,28 @@ +user()) { + return response()->json(['error' => 'Unauthorized'], 401); + } + + // Admin can access everything + if ($request->user()->isAdmin()) { + return $next($request); + } + + // For non-admin users, check if they have the required role + if (!in_array($request->user()->role, $roles)) { + return response()->json(['error' => 'Forbidden. You do not have the required role.'], 403); + } + + return $next($request); + } +} \ No newline at end of file diff --git a/TA_API/app/Http/Middleware/CorsMiddleware.php b/TA_API/app/Http/Middleware/CorsMiddleware.php new file mode 100644 index 0000000..8e44c96 --- /dev/null +++ b/TA_API/app/Http/Middleware/CorsMiddleware.php @@ -0,0 +1,39 @@ +isMethod('OPTIONS')) { + $response = response('', 200); + } else { + // Melanjutkan request + $response = $next($request); + } + + // Menambahkan header CORS + if ($response instanceof Response) { + $response->headers->set('Access-Control-Allow-Origin', '*'); + $response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); + $response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, X-XSRF-TOKEN, X-CSRF-TOKEN, Accept'); + $response->headers->set('Access-Control-Max-Age', '86400'); + $response->headers->set('Access-Control-Expose-Headers', 'Content-Disposition'); + } + + return $response; + } +} \ No newline at end of file diff --git a/TA_API/app/Models.zip b/TA_API/app/Models.zip new file mode 100644 index 0000000000000000000000000000000000000000..32e94468963e0ddece4eb0224b369da5789b9a4c GIT binary patch literal 6804 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 UV<7wz0Kh?fq!D2tNrwFQe`o{g;s5{u literal 0 HcmV?d00001 diff --git a/TA_API/app/Models/BankAccount.php b/TA_API/app/Models/BankAccount.php new file mode 100644 index 0000000..7b7f1a9 --- /dev/null +++ b/TA_API/app/Models/BankAccount.php @@ -0,0 +1,37 @@ + 'integer', + 'user_id' => 'integer', + 'verified_at' => 'datetime' + ]; + + public function user() + { + return $this->belongsTo(User::class); + } + + public function withdrawals() + { + return $this->hasMany(Withdrawal::class); + } +} \ No newline at end of file diff --git a/TA_API/app/Models/Booking.php b/TA_API/app/Models/Booking.php new file mode 100644 index 0000000..15d464c --- /dev/null +++ b/TA_API/app/Models/Booking.php @@ -0,0 +1,105 @@ + 'integer', + 'customer_id' => 'integer', + 'tailor_id' => 'integer', + 'total_price' => 'decimal:2', + 'appointment_date' => 'date', + 'appointment_time' => 'datetime:H:i', + 'completion_date' => 'date', + 'measurements' => 'array', + 'repair_details' => 'array', + 'accepted_at' => 'datetime', + 'rejected_at' => 'datetime', + 'completed_at' => 'datetime', + 'pickup_date' => 'date' + ]; + + /** + * Get the customer that owns the booking. + */ + public function customer() + { + return $this->belongsTo(User::class, 'customer_id'); + } + + /** + * Get the tailor that owns the booking. + */ + public function tailor() + { + return $this->belongsTo(User::class, 'tailor_id'); + } + + /** + * Get the ratings for the booking. + */ + public function ratings() + { + return $this->hasMany(TailorRating::class); + } + + /** + * Check if booking can be cancelled + */ + public function canBeCancelled() + { + return $this->status === 'reservasi'; + } + + /** + * Check if booking can be processed + */ + public function canBeProcessed() + { + return $this->status === 'reservasi' && $this->payment_status === 'paid'; + } + + /** + * Check if booking can be marked as completed + */ + public function canBeCompleted() + { + return $this->status === 'diproses'; + } +} \ No newline at end of file diff --git a/TA_API/app/Models/TailorGallery.php b/TA_API/app/Models/TailorGallery.php new file mode 100644 index 0000000..06de347 --- /dev/null +++ b/TA_API/app/Models/TailorGallery.php @@ -0,0 +1,32 @@ + 'integer', + 'user_id' => 'integer' + ]; + + /** + * Get the tailor that owns the gallery item + */ + public function tailor() + { + return $this->belongsTo(User::class, 'user_id'); + } +} \ No newline at end of file diff --git a/TA_API/app/Models/TailorRating.php b/TA_API/app/Models/TailorRating.php new file mode 100644 index 0000000..8360090 --- /dev/null +++ b/TA_API/app/Models/TailorRating.php @@ -0,0 +1,51 @@ + 'integer', + 'booking_id' => 'integer', + 'customer_id' => 'integer', + 'tailor_id' => 'integer', + 'rating' => 'decimal:1' + ]; + + /** + * Get the booking that owns the rating. + */ + public function booking() + { + return $this->belongsTo(Booking::class); + } + + /** + * Get the customer who gave the rating. + */ + public function customer() + { + return $this->belongsTo(User::class, 'customer_id'); + } + + /** + * Get the tailor who received the rating. + */ + public function tailor() + { + return $this->belongsTo(User::class, 'tailor_id'); + } +} \ No newline at end of file diff --git a/TA_API/app/Models/TailorService.php b/TA_API/app/Models/TailorService.php new file mode 100644 index 0000000..8182e1c --- /dev/null +++ b/TA_API/app/Models/TailorService.php @@ -0,0 +1,38 @@ + 'integer', + 'user_id' => 'integer', + 'price' => 'decimal:2', + 'estimated_days' => 'integer', + 'is_available' => 'boolean' + ]; + + /** + * Get the tailor that owns the service + */ + public function tailor() + { + return $this->belongsTo(User::class, 'user_id'); + } +} \ No newline at end of file diff --git a/TA_API/app/Models/TailorSpecialization.php b/TA_API/app/Models/TailorSpecialization.php new file mode 100644 index 0000000..4549fa7 --- /dev/null +++ b/TA_API/app/Models/TailorSpecialization.php @@ -0,0 +1,29 @@ + 'integer' + ]; + + /** + * The tailors that belong to the specialization. + */ + public function tailors() + { + return $this->belongsToMany(User::class, 'tailor_specialization_user') + ->where('role', 'penjahit'); + } +} \ No newline at end of file diff --git a/TA_API/app/Models/User.php b/TA_API/app/Models/User.php new file mode 100644 index 0000000..9f84996 --- /dev/null +++ b/TA_API/app/Models/User.php @@ -0,0 +1,190 @@ + */ + use HasApiTokens, HasFactory, Notifiable; + + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'name', + 'email', + 'password', + 'role', + 'phone_number', + 'address', + 'shop_description', + 'profile_photo', + 'latitude', + 'longitude', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var array + */ + protected $hidden = [ + 'password', + 'remember_token', + ]; + + /** + * Get the attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + 'id' => 'integer', + 'latitude' => 'float', + 'longitude' => 'float', + ]; + + /** + * Check if user is admin + */ + public function isAdmin(): bool + { + return $this->role === 'admin'; + } + + /** + * Check if user is penjahit + */ + public function isPenjahit(): bool + { + return $this->role === 'penjahit'; + } + + /** + * Check if user is pelanggan + */ + public function isPelanggan(): bool + { + return $this->role === 'pelanggan'; + } + + /** + * Check if user has specific role + */ + public function hasRole(string $role): bool + { + return $this->role === $role; + } + + /** + * Get the specializations for the tailor. + */ + public function specializations() + { + return $this->belongsToMany(TailorSpecialization::class, 'tailor_specialization_user'); + } + + /** + * Get the preferred specializations for the customer. + */ + public function preferredSpecializations() + { + return $this->belongsToMany(TailorSpecialization::class, 'customer_specialization'); + } + + /** + * Get the services for the tailor. + */ + public function services() + { + return $this->hasMany(TailorService::class, 'user_id'); + } + + /** + * Get the bookings for the user (as customer). + */ + public function customerBookings() + { + return $this->hasMany(Booking::class, 'customer_id'); + } + + /** + * Get the bookings for the user (as tailor). + */ + public function bookings() + { + return $this->hasMany(Booking::class, 'tailor_id'); + } + + /** + * Get the gallery items for the tailor. + */ + public function gallery() + { + return $this->hasMany(TailorGallery::class, 'user_id'); + } + + /** + * Get the ratings for the tailor. + */ + public function ratings() + { + return $this->hasMany(TailorRating::class, 'tailor_id'); + } + + /** + * Get the ratings given by the customer. + */ + public function givenRatings() + { + return $this->hasMany(TailorRating::class, 'customer_id'); + } + + /** + * Send the password reset notification. + * + * @param string $token + * @return void + */ + public function sendPasswordResetNotification($token) + { + $this->notify(new ResetPasswordNotification($token)); + } + + public function wallet() + { + return $this->hasOne(Wallet::class); + } + + public function bankAccounts() + { + return $this->hasMany(BankAccount::class); + } + + /** + * Kirim notifikasi verifikasi email custom + */ + public function sendEmailVerificationNotification() + { + // Generate verification URL yang langsung mengarah ke backend + $verificationUrl = url()->temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $this->id, 'hash' => sha1($this->email)] + ); + + $this->notify(new \App\Notifications\VerifyEmailNotification($verificationUrl)); + } +} diff --git a/TA_API/app/Models/Wallet.php b/TA_API/app/Models/Wallet.php new file mode 100644 index 0000000..645dfe0 --- /dev/null +++ b/TA_API/app/Models/Wallet.php @@ -0,0 +1,67 @@ + 'integer', + 'user_id' => 'integer', + 'balance' => 'float' + ]; + + public function user() + { + return $this->belongsTo(User::class); + } + + public function transactions() + { + return $this->hasMany(WalletTransaction::class); + } + + public function withdrawals() + { + return $this->hasMany(Withdrawal::class); + } + + public function addBalance($amount, $description, $booking = null) + { + $this->balance += $amount; + $this->save(); + + $this->transactions()->create([ + 'type' => 'credit', + 'amount' => $amount, + 'description' => $description, + 'booking_id' => $booking ? $booking->id : null + ]); + } + + public function deductBalance($amount, $description) + { + if ($this->balance < $amount) { + throw new \Exception('Insufficient balance'); + } + + $this->balance -= $amount; + $this->save(); + + $this->transactions()->create([ + 'type' => 'debit', + 'amount' => $amount, + 'description' => $description + ]); + } +} \ No newline at end of file diff --git a/TA_API/app/Models/WalletTransaction.php b/TA_API/app/Models/WalletTransaction.php new file mode 100644 index 0000000..d420d90 --- /dev/null +++ b/TA_API/app/Models/WalletTransaction.php @@ -0,0 +1,37 @@ + 'integer', + 'wallet_id' => 'integer', + 'booking_id' => 'integer', + 'amount' => 'float' + ]; + + public function wallet() + { + return $this->belongsTo(Wallet::class); + } + + public function booking() + { + return $this->belongsTo(Booking::class); + } +} \ No newline at end of file diff --git a/TA_API/app/Models/Withdrawal.php b/TA_API/app/Models/Withdrawal.php new file mode 100644 index 0000000..f435773 --- /dev/null +++ b/TA_API/app/Models/Withdrawal.php @@ -0,0 +1,39 @@ + 'integer', + 'wallet_id' => 'integer', + 'bank_account_id' => 'integer', + 'amount' => 'float', + 'processed_at' => 'datetime' + ]; + + public function wallet() + { + return $this->belongsTo(Wallet::class); + } + + public function bankAccount() + { + return $this->belongsTo(BankAccount::class); + } +} \ No newline at end of file diff --git a/TA_API/app/Notifications/ResetPasswordNotification.php b/TA_API/app/Notifications/ResetPasswordNotification.php new file mode 100644 index 0000000..4614d09 --- /dev/null +++ b/TA_API/app/Notifications/ResetPasswordNotification.php @@ -0,0 +1,62 @@ +pin = $pin; + } + + /** + * Get the notification's delivery channels. + * + * @return array + */ + public function via(object $notifiable): array + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + */ + public function toMail(object $notifiable): MailMessage + { + $appName = config('app.name', 'Project Jahit'); + + return (new MailMessage) + ->subject('Reset Password - ' . $appName) + ->view('emails.reset-password', [ + 'pin' => $this->pin, + 'name' => $notifiable->name, + 'appName' => $appName, + 'expiresIn' => '60 menit' + ]); + } + + /** + * Get the array representation of the notification. + * + * @return array + */ + public function toArray(object $notifiable): array + { + return [ + 'pin' => $this->pin, + ]; + } +} \ No newline at end of file diff --git a/TA_API/app/Notifications/VerifyEmailNotification.php b/TA_API/app/Notifications/VerifyEmailNotification.php new file mode 100644 index 0000000..e259bb5 --- /dev/null +++ b/TA_API/app/Notifications/VerifyEmailNotification.php @@ -0,0 +1,65 @@ +verificationUrl = $verificationUrl; + } + + /** + * Get the notification's delivery channels. + * + * @return array + */ + public function via(object $notifiable): array + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + */ + public function toMail(object $notifiable): MailMessage + { + $appName = config('app.name', 'Project Jahit'); + + return (new MailMessage) + ->subject('Verifikasi Email - ' . $appName) + ->view('emails.verify-email', [ + 'url' => $this->verificationUrl, + 'name' => $notifiable->name, + 'appName' => $appName, + 'expiresIn' => '60 menit' + ]); + } + + /** + * Get the array representation of the notification. + * + * @return array + */ + public function toArray(object $notifiable): array + { + return [ + 'verification_url' => $this->verificationUrl, + ]; + } +} \ No newline at end of file diff --git a/TA_API/app/Providers/AppServiceProvider.php b/TA_API/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..6bc051f --- /dev/null +++ b/TA_API/app/Providers/AppServiceProvider.php @@ -0,0 +1,28 @@ + + */ + protected $policies = [ + // + ]; + + /** + * Register any authentication / authorization services. + */ + public function boot(): void + { + $this->registerPolicies(); + + // Define gates for roles + Gate::define('admin', function ($user) { + return $user->role === 'admin'; + }); + + Gate::define('penjahit', function ($user) { + return $user->role === 'penjahit'; + }); + + Gate::define('pelanggan', function ($user) { + return $user->role === 'pelanggan'; + }); + } +} \ No newline at end of file diff --git a/TA_API/app/Providers/EventServiceProvider.php b/TA_API/app/Providers/EventServiceProvider.php new file mode 100644 index 0000000..164c70e --- /dev/null +++ b/TA_API/app/Providers/EventServiceProvider.php @@ -0,0 +1,38 @@ +> + */ + protected $listen = [ + Registered::class => [ + SendEmailVerificationNotification::class, + ], + ]; + + /** + * Register any events for your application. + */ + public function boot(): void + { + // + } + + /** + * Determine if events and listeners should be automatically discovered. + */ + public function shouldDiscoverEvents(): bool + { + return false; + } +} \ No newline at end of file diff --git a/TA_API/app/Providers/RouteServiceProvider.php b/TA_API/app/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..fc97ddd --- /dev/null +++ b/TA_API/app/Providers/RouteServiceProvider.php @@ -0,0 +1,40 @@ +by($request->user()?->id ?: $request->ip()); + }); + + $this->routes(function () { + Route::middleware('api') + ->prefix('api') + ->group(base_path('routes/api.php')); + + Route::middleware('web') + ->group(base_path('routes/web.php')); + }); + } +} \ No newline at end of file diff --git a/TA_API/artisan b/TA_API/artisan new file mode 100644 index 0000000..c35e31d --- /dev/null +++ b/TA_API/artisan @@ -0,0 +1,18 @@ +#!/usr/bin/env php +handleCommand(new ArgvInput); + +exit($status); diff --git a/TA_API/bacaini.md b/TA_API/bacaini.md new file mode 100644 index 0000000..47594d5 --- /dev/null +++ b/TA_API/bacaini.md @@ -0,0 +1,578 @@ +1. PENJAHIT +A. REGISTER +http://localhost:8000/api/penjahit/register + { + "name": "Toko Jahit Makmur", + "email": "jahit.makmur@example.com", + "password": "password123", + "phone_number": "081234567891", + "address": "Jl. Menjahit Indah No. 123, Jakarta Selatan", + "shop_description": "Toko jahit terpercaya dengan pengalaman lebih dari 10 tahun. Menyediakan berbagai jasa jahit dan perbaikan pakaian dengan kualitas premium.", + "specializations": [1, 2] + } +B. Login +http://localhost:8000/api/penjahit/login +{ + "email": "jahit.makmurr@example.com", + "password": "password" +} +C. DASHBOARD +GET http://localhost:8000/api/penjahit/dashboard +INI RESPON +{ + "success": true, + "data": { + "incoming_bookings": [], + "current_month_earnings": 0, + "total_earnings": 0, + "average_rating": 0, + "total_completed_orders": 0 + }, + "message": "Data dashboard berhasil diambil" +} + +D.DI FIGMA HALAMAN KONFIRMASI PESANAN +GET http://localhost:8000/api/penjahit/bookings/status/pending +GET http://localhost:8000/api/penjahit/bookings/status/diterima +GET http://localhost:8000/api/penjahit/bookings/status/diproses +GET http://localhost:8000/api/penjahit/bookings/status/selesai +GET http://localhost:8000/api/penjahit/bookings/status/dibatalkan +ALL http://localhost:8000/api/penjahit/bookings + +E. TERIMA DAN TOLAK berdasarkan ia login +POST http://localhost:8000/api/bookings/{booking_id}/reject +POST http://localhost:8000/api/bookings/{booking_id}/accept + +F. KALENDER GET +http://localhost:8000/api/penjahit/calendar/3/2025 +{ + "success": true, + "data": { + "month": 3, + "year": 2025, + "month_name": "March", + "calendar": [ + { + "date": "2025-03-01", + "day": "01", + "day_name": "Saturday", + "bookings": [] + }, + { + "date": "2025-03-02", + "day": "02", + "day_name": "Sunday", + "bookings": [] + }, + { + "date": "2025-03-03", + "day": "03", + "day_name": "Monday", + "bookings": [] + }, + { + "date": "2025-03-04", + "day": "04", + "day_name": "Tuesday", + "bookings": [] + }, + { + "date": "2025-03-05", + "day": "05", + "day_name": "Wednesday", + "bookings": [] + }, + { + "date": "2025-03-06", + "day": "06", + "day_name": "Thursday", + "bookings": [] + }, + { + "date": "2025-03-07", + "day": "07", + "day_name": "Friday", + "bookings": [] + }, + { + "date": "2025-03-08", + "day": "08", + "day_name": "Saturday", + "bookings": [] + }, + { + "date": "2025-03-09", + "day": "09", + "day_name": "Sunday", + "bookings": [] + }, + { + "date": "2025-03-10", + "day": "10", + "day_name": "Monday", + "bookings": [] + }, + { + "date": "2025-03-11", + "day": "11", + "day_name": "Tuesday", + "bookings": [] + }, + { + "date": "2025-03-12", + "day": "12", + "day_name": "Wednesday", + "bookings": [] + }, + { + "date": "2025-03-13", + "day": "13", + "day_name": "Thursday", + "bookings": [] + }, + { + "date": "2025-03-14", + "day": "14", + "day_name": "Friday", + "bookings": [] + }, + { + "date": "2025-03-15", + "day": "15", + "day_name": "Saturday", + "bookings": [] + }, + { + "date": "2025-03-16", + "day": "16", + "day_name": "Sunday", + "bookings": [] + }, + { + "date": "2025-03-17", + "day": "17", + "day_name": "Monday", + "bookings": [] + }, + { + "date": "2025-03-18", + "day": "18", + "day_name": "Tuesday", + "bookings": [] + }, + { + "date": "2025-03-19", + "day": "19", + "day_name": "Wednesday", + "bookings": [] + }, + { + "date": "2025-03-20", + "day": "20", + "day_name": "Thursday", + "bookings": [] + }, + { + "date": "2025-03-21", + "day": "21", + "day_name": "Friday", + "bookings": [] + }, + { + "date": "2025-03-22", + "day": "22", + "day_name": "Saturday", + "bookings": [] + }, + { + "date": "2025-03-23", + "day": "23", + "day_name": "Sunday", + "bookings": [] + }, + { + "date": "2025-03-24", + "day": "24", + "day_name": "Monday", + "bookings": [] + }, + { + "date": "2025-03-25", + "day": "25", + "day_name": "Tuesday", + "bookings": [] + }, + { + "date": "2025-03-26", + "day": "26", + "day_name": "Wednesday", + "bookings": [] + }, + { + "date": "2025-03-27", + "day": "27", + "day_name": "Thursday", + "bookings": [ + { + "id": 2, + "time": "2025-03-26T10:00:00.000000Z", + "customer_name": "Rudi Hermawan", + "customer_phone": "081234567895", + "service_type": "Jahit Baru", + "category": "Bawahan", + "status": "diproses", + "payment_status": "paid" + } + ] + }, + { + "date": "2025-03-28", + "day": "28", + "day_name": "Friday", + "bookings": [] + }, + { + "date": "2025-03-29", + "day": "29", + "day_name": "Saturday", + "bookings": [] + }, + { + "date": "2025-03-30", + "day": "30", + "day_name": "Sunday", + "bookings": [] + }, + { + "date": "2025-03-31", + "day": "31", + "day_name": "Monday", + "bookings": [] + } + ], + "summary": { + "total_bookings": 1, + "pending_bookings": 0, + "ongoing_bookings": 1, + "completed_bookings": 0, + "cancelled_bookings": 0 + } + }, + "message": "Data kalender berhasil diambil" +} + + + + + + + +2. USERS +A. REGISTER +http://localhost:8000/api/pelanggan/register +{ + "name": "Pelanggan Baru", + "email": "pelanggan.baru22@example.com", + "password": "password123", + "phone_number": "081234567890", + "address": "Jl. Pelanggan No. 123, Jakarta", + "preferred_specializations": [3, 5, 9], + "latitude": -6.1754, + "longitude": 106.8272 +} +B. Login +http://localhost:8000/api/pelanggan/login +{ + "email": "pelanggan2@gmail.com", + "password": "password" +} +C. DASHBOARD +http://localhost:8000/api/tailors/recommended +{ + "success": true, + "data": { + "tailors": [ + { + "id": 3, + "name": "Siti Rahayu", + "email": "siti@example.com", + "role": "penjahit", + "phone_number": "081234567892", + "address": "Jl. Penjahit No. 2", + "latitude": null, + "longitude": null, + "shop_description": null, + "profile_photo": null, + "email_verified_at": null, + "created_at": "2025-03-24T21:15:14.000000Z", + "updated_at": "2025-03-24T21:15:14.000000Z", + "distance": null, + "specializations": [ + { + "id": 8, + "name": "Gamis", + "icon": null, + "created_at": "2025-03-23T14:12:26.000000Z", + "updated_at": "2025-03-23T14:12:26.000000Z", + "pivot": { + "user_id": 3, + "tailor_specialization_id": 8 + } + }, + { + "id": 9, + "name": "Baju Pesta", + "icon": "dress", + "created_at": "2025-03-24T21:15:13.000000Z", + "updated_at": "2025-03-24T21:15:13.000000Z", + "pivot": { + "user_id": 3, + "tailor_specialization_id": 9 + } + } + ] + } + ], + "user_preferred": [ + 3, + 5, + 9 + ] + }, + "message": "Rekomendasi penjahit berhasil diambil" +} + +D. DETAIL PENJAHIT +http://localhost:8000/api/tailors/3 + +{ + "success": true, + "data": { + "id": 3, + "name": "Siti Rahayu", + "email": "siti@example.com", + "role": "penjahit", + "phone_number": "081234567892", + "address": "Jl. Penjahit No. 2", + "latitude": null, + "longitude": null, + "shop_description": null, + "profile_photo": null, + "email_verified_at": null, + "created_at": "2025-03-24T21:15:14.000000Z", + "updated_at": "2025-03-24T21:15:14.000000Z", + "completed_orders": 0, + "average_rating": 4, + "distance": null, + "specializations": [ + { + "id": 8, + "name": "Gamis", + "icon": null, + "created_at": "2025-03-23T14:12:26.000000Z", + "updated_at": "2025-03-23T14:12:26.000000Z", + "pivot": { + "user_id": 3, + "tailor_specialization_id": 8 + } + }, + { + "id": 9, + "name": "Baju Pesta", + "icon": "dress", + "created_at": "2025-03-24T21:15:13.000000Z", + "updated_at": "2025-03-24T21:15:13.000000Z", + "pivot": { + "user_id": 3, + "tailor_specialization_id": 9 + } + } + ], + "services": [ + { + "id": 2, + "user_id": 3, + "name": "Jahit Baju Muslim", + "description": "Jahit baju muslim dengan desain modern", + "price": "350000.00", + "category": "Jahit Baru", + "estimated_days": 5, + "is_available": true, + "service_photo": "services/baju_muslim.jpg", + "created_at": "2025-03-24T21:15:15.000000Z", + "updated_at": "2025-03-24T21:15:15.000000Z" + } + ] + }, + "message": "Detail penjahit berhasil diambil" +} + +E. Melakukan booking +http://localhost:8000/api/tailors/3/book +INI PERINTAHNYA +{ + "appointment_date": "2025-04-01", + "appointment_time": "14:00", + "service_type": "Jahit Baru", + "category": "Bawahan", + "notes": "Celana bahan katun warna hitam", + "measurements": [ + { + "name": "lingkar_pinggang", + "value": 82, + "unit": "cm" + }, + { + "name": "lingkar_pinggul", + "value": 96, + "unit": "cm" + }, + { + "name": "panjang_celana", + "value": 98, + "unit": "cm" + }, + { + "name": "lingkar_paha", + "value": 58, + "unit": "cm" + }, + { + "name": "lingkar_lutut", + "value": 40, + "unit": "cm" + }, + { + "name": "lingkar_kaki", + "value": 32, + "unit": "cm" + } + ] +} +F. Untuk get semua bookings +http://localhost:8000/api/bookings/customer +ini responnya +{ + "success": true, + "data": [ + { + "id": 5, + "customer_id": 13, + "tailor_id": 3, + "appointment_date": "2025-04-01T00:00:00.000000Z", + "appointment_time": "14:00", + "service_type": "Jahit Baru", + "category": "Bawahan", + "design_photo": null, + "notes": "Celana bahan katun warna hitam", + "status": "reservasi", + "total_price": null, + "payment_status": "unpaid", + "measurements": [ + { + "name": "lingkar_pinggang", + "unit": "cm", + "value": 82 + }, + { + "name": "lingkar_pinggul", + "unit": "cm", + "value": 96 + }, + { + "name": "panjang_celana", + "unit": "cm", + "value": 98 + }, + { + "name": "lingkar_paha", + "unit": "cm", + "value": 58 + }, + { + "name": "lingkar_lutut", + "unit": "cm", + "value": 40 + }, + { + "name": "lingkar_kaki", + "unit": "cm", + "value": 32 + } + ], + "repair_details": null, + "repair_photo": null, + "repair_notes": null, + "completion_photo": null, + "completion_notes": null, + "accepted_at": null, + "rejected_at": null, + "completed_at": null, + "rejection_reason": null, + "created_at": "2025-03-25T08:10:03.000000Z", + "updated_at": "2025-03-25T08:10:03.000000Z", + "tailor": { + "id": 3, + "name": "Siti Rahayu", + "email": "siti@example.com", + "role": "penjahit", + "phone_number": "081234567892", + "address": "Jl. Penjahit No. 2", + "latitude": null, + "longitude": null, + "shop_description": null, + "profile_photo": null, + "email_verified_at": null, + "created_at": "2025-03-24T21:15:14.000000Z", + "updated_at": "2025-03-24T21:15:14.000000Z" + } + }, + { + "id": 4, + "customer_id": 13, + "tailor_id": 3, + "appointment_date": "2025-04-01T00:00:00.000000Z", + "appointment_time": "14:00", + "service_type": "Jahit Baru", + "category": "Bawahan", + "design_photo": null, + "notes": "Jahit celana panjang dengan bahan katun", + "status": "reservasi", + "total_price": null, + "payment_status": "unpaid", + "measurements": null, + "repair_details": null, + "repair_photo": null, + "repair_notes": null, + "completion_photo": null, + "completion_notes": null, + "accepted_at": null, + "rejected_at": null, + "completed_at": null, + "rejection_reason": null, + "created_at": "2025-03-25T07:59:47.000000Z", + "updated_at": "2025-03-25T07:59:47.000000Z", + "tailor": { + "id": 3, + "name": "Siti Rahayu", + "email": "siti@example.com", + "role": "penjahit", + "phone_number": "081234567892", + "address": "Jl. Penjahit No. 2", + "latitude": null, + "longitude": null, + "shop_description": null, + "profile_photo": null, + "email_verified_at": null, + "created_at": "2025-03-24T21:15:14.000000Z", + "updated_at": "2025-03-24T21:15:14.000000Z" + } + } + ], + "message": "Data booking berhasil diambil." +} +GET BOOKING BERDASRKAN STATUS +GET http://localhost:8000/api/bookings/customer/status/reservasi +GET http://localhost:8000/api/bookings/customer/status/diproses +GET http://localhost:8000/api/bookings/customer/status/selesai +GET http://localhost:8000/api/bookings/customer/status/dibatalkan diff --git a/TA_API/bootstrap/app.php b/TA_API/bootstrap/app.php new file mode 100644 index 0000000..7b162da --- /dev/null +++ b/TA_API/bootstrap/app.php @@ -0,0 +1,18 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware) { + // + }) + ->withExceptions(function (Exceptions $exceptions) { + // + })->create(); diff --git a/TA_API/bootstrap/cache/.gitignore b/TA_API/bootstrap/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/bootstrap/providers.php b/TA_API/bootstrap/providers.php new file mode 100644 index 0000000..38b258d --- /dev/null +++ b/TA_API/bootstrap/providers.php @@ -0,0 +1,5 @@ +=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.0.10", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.10" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2024-02-18T20:23:39+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "8c784d071debd117328803d86b2097615b457500" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", + "reference": "8c784d071debd117328803d86b2097615b457500", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.0" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2024-10-09T13:47:03+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2025-03-06T22:45:56+00:00" + }, + { + "name": "fruitcake/php-cors", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "symfony/http-foundation": "^4.4|^5.4|^6|^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barryvdh", + "email": "barryvdh@gmail.com" + } + ], + "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", + "homepage": "https://github.com/fruitcake/php-cors", + "keywords": [ + "cors", + "laravel", + "symfony" + ], + "support": { + "issues": "https://github.com/fruitcake/php-cors/issues", + "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2023-10-12T05:21:21+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2024-10-17T10:06:22+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "uri-template/tests": "1.0.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\UriTemplate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + } + ], + "description": "A polyfill class for uri_template of PHP", + "keywords": [ + "guzzlehttp", + "uri-template" + ], + "support": { + "issues": "https://github.com/guzzle/uri-template/issues", + "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/uri-template", + "type": "tidelift" + } + ], + "time": "2025-02-03T10:55:03+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.3.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "ca0412e978f78ecea0cafbe34dd8b18010064f73" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/ca0412e978f78ecea0cafbe34dd8b18010064f73", + "reference": "ca0412e978f78ecea0cafbe34dd8b18010064f73", + "shasum": "" + }, + "require": { + "brick/math": "^0.11|^0.12", + "composer-runtime-api": "^2.2", + "doctrine/inflector": "^2.0.5", + "dragonmantank/cron-expression": "^3.4", + "egulias/email-validator": "^3.2.1|^4.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-session": "*", + "ext-tokenizer": "*", + "fruitcake/php-cors": "^1.3", + "guzzlehttp/guzzle": "^7.8.2", + "guzzlehttp/uri-template": "^1.0", + "laravel/prompts": "^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "league/commonmark": "^2.6", + "league/flysystem": "^3.25.1", + "league/flysystem-local": "^3.25.1", + "league/uri": "^7.5.1", + "monolog/monolog": "^3.0", + "nesbot/carbon": "^3.8.4", + "nunomaduro/termwind": "^2.0", + "php": "^8.2", + "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", + "symfony/polyfill-php83": "^1.31", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.5", + "vlucas/phpdotenv": "^5.6.1", + "voku/portable-ascii": "^2.0.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "psr/log-implementation": "1.0|2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/collections": "self.version", + "illuminate/concurrency": "self.version", + "illuminate/conditionable": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/macroable": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/process": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/testing": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "spatie/once": "*" + }, + "require-dev": { + "ably/ably-php": "^1.0", + "aws/aws-sdk-php": "^3.322.9", + "ext-gmp": "*", + "fakerphp/faker": "^1.24", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", + "league/flysystem-aws-s3-v3": "^3.25.1", + "league/flysystem-ftp": "^3.25.1", + "league/flysystem-path-prefixing": "^3.25.1", + "league/flysystem-read-only": "^3.25.1", + "league/flysystem-sftp-v3": "^3.25.1", + "mockery/mockery": "^1.6.10", + "orchestra/testbench-core": "^10.0.0", + "pda/pheanstalk": "^5.0.6", + "php-http/discovery": "^1.15", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3", + "resend/resend-php": "^0.10.0", + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" + }, + "suggest": { + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", + "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", + "ext-apcu": "Required to use the APC cache driver.", + "ext-fileinfo": "Required to use the Filesystem class.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", + "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.", + "ext-pdo": "Required to use all database features.", + "ext-posix": "Required to use all features of the queue worker.", + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", + "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).", + "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", + "mockery/mockery": "Required to use mocking (^1.6).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", + "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).", + "predis/predis": "Required to use the predis connector (^2.3).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", + "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Collections/functions.php", + "src/Illuminate/Collections/helpers.php", + "src/Illuminate/Events/functions.php", + "src/Illuminate/Filesystem/functions.php", + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Log/functions.php", + "src/Illuminate/Support/functions.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/", + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-03-18T13:49:19+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.3.5", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/console": "^6.2|^7.0" + }, + "conflict": { + "illuminate/console": ">=10.17.0 <10.25.0", + "laravel/framework": ">=10.17.0 <10.25.0" + }, + "require-dev": { + "illuminate/collections": "^10.0|^11.0|^12.0", + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3|^3.4", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-mockery": "^1.1" + }, + "suggest": { + "ext-pcntl": "Required for the spinner to be animated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.3.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Laravel\\Prompts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Add beautiful and user-friendly forms to your command-line applications.", + "support": { + "issues": "https://github.com/laravel/prompts/issues", + "source": "https://github.com/laravel/prompts/tree/v0.3.5" + }, + "time": "2025-02-11T13:34:40+00:00" + }, + { + "name": "laravel/sanctum", + "version": "v4.0.8", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/ec1dd9ddb2ab370f79dfe724a101856e0963f43c", + "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^11.0|^12.0", + "illuminate/contracts": "^11.0|^12.0", + "illuminate/database": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "php": "^8.2", + "symfony/console": "^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "orchestra/testbench": "^9.0|^10.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2025-01-26T19:34:36+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "f379c13663245f7aa4512a7869f62eb14095f23f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f379c13663245f7aa4512a7869f62eb14095f23f", + "reference": "f379c13663245f7aa4512a7869f62eb14095f23f", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2025-02-11T15:03:05+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.10.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "php": "^7.2.5|^8.0", + "psy/psysh": "^0.11.1|^0.12.0", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" + }, + "require-dev": { + "mockery/mockery": "~1.3.3|^1.4.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "support": { + "issues": "https://github.com/laravel/tinker/issues", + "source": "https://github.com/laravel/tinker/tree/v2.10.1" + }, + "time": "2025-01-27T14:24:01+00:00" + }, + { + "name": "league/commonmark", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d990688c91cedfb69753ffc2512727ec646df2ad", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2024-12-29T14:10:59+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "league/flysystem", + "version": "3.29.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319", + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.29.1" + }, + "time": "2024-10-08T08:58:34+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.29.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0" + }, + "time": "2024-08-09T21:24:39+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-09-21T08:32:55+00:00" + }, + { + "name": "league/uri", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "league/uri-components": "Needed to easily manipulate URI objects components", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:18:47+00:00" + }, + { + "name": "midtrans/midtrans-php", + "version": "2.6.2", + "source": { + "type": "git", + "url": "https://github.com/Midtrans/midtrans-php.git", + "reference": "8ed7fc58ff1ababe675da17acf8233f4028eb3be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Midtrans/midtrans-php/zipball/8ed7fc58ff1ababe675da17acf8233f4028eb3be", + "reference": "8ed7fc58ff1ababe675da17acf8233f4028eb3be", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-openssl": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "5.7.*", + "psy/psysh": "0.4.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "SnapBi\\": "SnapBi/", + "Midtrans\\": "Midtrans/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andri Setiawan", + "email": "andri.setiawan@veritrans.co.id" + }, + { + "name": "Alvin Litani", + "email": "alvin.litani@veritrans.co.id" + }, + { + "name": "Ismail Faruqi", + "email": "ismail.faruqi@veritrans.co.id" + }, + { + "name": "Muhammad Fauzi Masykur", + "email": "muhammad.masykur@gojek.com" + } + ], + "description": "PHP Wrapper for Midtrans Payment API.", + "homepage": "https://midtrans.com", + "support": { + "issues": "https://github.com/Midtrans/midtrans-php/issues", + "source": "https://github.com/Midtrans/midtrans-php/tree/v2.6.2" + }, + "time": "2025-03-18T06:30:17+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.8.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.8.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2024-12-05T17:15:07+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.8.6", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ff2f20cf83bd4d503720632ce8a426dc747bf7fd", + "reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3 || ^7.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.57.2", + "kylekatarnls/multi-tester": "^2.5.3", + "ondrejmirtes/better-reflection": "^6.25.0.4", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.11.2", + "phpunit/phpunit": "^10.5.20", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2025-02-20T17:33:38+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.5.2", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.2" + }, + "time": "2024-10-06T23:10:23+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.5", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", + "shasum": "" + }, + "require": { + "php": "8.0 - 8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.5" + }, + "time": "2024-08-07T15:39:19+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/52915afe6a1044e8b9cee1bcff836fb63acf9cda", + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.1.8" + }, + "require-dev": { + "illuminate/console": "^11.33.2", + "laravel/pint": "^1.18.2", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0", + "phpstan/phpstan": "^1.12.11", + "phpstan/phpstan-strict-rules": "^1.6.1", + "symfony/var-dumper": "^7.1.8", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Its like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2024-11-21T10:39:51+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:41:07+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.12.8", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": false, + "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.8" + }, + "time": "2025-03-16T03:05:19+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/collection", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.1.1" + }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.7.6", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", + "ext-json": "*", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.8", + "ergebnis/composer-normalize": "^2.15", + "mockery/mockery": "^1.3", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", + "php-mock/php-mock-mockery": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.7.6" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "time": "2024-04-27T21:32:50+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/console", + "version": "v7.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-11T03:49:26+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/aabf79938aa795350c07ce6464dd1985607d95d5", + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-02T20:27:07+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:17+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ee1b504b8926198be89d05e5b6fc4c3810c090f0", + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T10:56:55+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "9f1103734c5789798fefb90e91de4586039003ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f1103734c5789798fefb90e91de4586039003ed", + "reference": "9f1103734c5789798fefb90e91de4586039003ed", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^7.1", + "symfony/routing": "^6.4|^7.0", + "symfony/serializer": "^7.1", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-26T11:01:22+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f3871b182c44997cf039f3b462af4a48fb85f9d3", + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/mime": "^7.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-27T11:08:17+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/87ca22046b78c3feaff04b337f33b38510fd686b", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-19T08:51:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-05T08:33:46+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/ee9a67edc6baa33e5fae662f94f91fd262930996", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T10:56:55+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-13T13:31:26+00:00" + }, + { + "name": "symfony/translation", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/283856e6981286cc0d800b53bd5703e8e363f05a", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^4.18|^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-13T10:27:23+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/82b478c69745d8878eb60f9a049a4d584996f73a", + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T11:39:41+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + }, + "time": "2024-12-21T16:25:41+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:52:34+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "https://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2024-11-21T01:49:47+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "packages-dev": [ + { + "name": "barryvdh/laravel-ide-helper", + "version": "v3.5.5", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-ide-helper.git", + "reference": "8d441ec99f8612b942b55f5183151d91591b618a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/8d441ec99f8612b942b55f5183151d91591b618a", + "reference": "8d441ec99f8612b942b55f5183151d91591b618a", + "shasum": "" + }, + "require": { + "barryvdh/reflection-docblock": "^2.3", + "composer/class-map-generator": "^1.0", + "ext-json": "*", + "illuminate/console": "^11.15 || ^12", + "illuminate/database": "^11.15 || ^12", + "illuminate/filesystem": "^11.15 || ^12", + "illuminate/support": "^11.15 || ^12", + "php": "^8.2" + }, + "require-dev": { + "ext-pdo_sqlite": "*", + "friendsofphp/php-cs-fixer": "^3", + "illuminate/config": "^11.15 || ^12", + "illuminate/view": "^11.15 || ^12", + "mockery/mockery": "^1.4", + "orchestra/testbench": "^9.2 || ^10", + "phpunit/phpunit": "^10.5 || ^11.5.3", + "spatie/phpunit-snapshot-assertions": "^4 || ^5", + "vimeo/psalm": "^5.4", + "vlucas/phpdotenv": "^5" + }, + "suggest": { + "illuminate/events": "Required for automatic helper generation (^6|^7|^8|^9|^10|^11)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\LaravelIdeHelper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.", + "keywords": [ + "autocomplete", + "codeintel", + "dev", + "helper", + "ide", + "laravel", + "netbeans", + "phpdoc", + "phpstorm", + "sublime" + ], + "support": { + "issues": "https://github.com/barryvdh/laravel-ide-helper/issues", + "source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.5.5" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2025-02-11T13:59:46+00:00" + }, + { + "name": "barryvdh/reflection-docblock", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/ReflectionDocBlock.git", + "reference": "b6ff9f93603561f50e53b64310495d20b8dff5d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/b6ff9f93603561f50e53b64310495d20b8dff5d8", + "reference": "b6ff9f93603561f50e53b64310495d20b8dff5d8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.14|^9" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Barryvdh": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "support": { + "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.3.1" + }, + "time": "2025-01-18T19:26:32+00:00" + }, + { + "name": "composer/class-map-generator", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/composer/class-map-generator.git", + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/134b705ddb0025d397d8318a75825fe3c9d1da34", + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34", + "shasum": "" + }, + "require": { + "composer/pcre": "^2.1 || ^3.1", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\ClassMapGenerator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Utilities to scan PHP code and generate class maps.", + "keywords": [ + "classmap" + ], + "support": { + "issues": "https://github.com/composer/class-map-generator/issues", + "source": "https://github.com/composer/class-map-generator/tree/1.6.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-03-24T13:50:44+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "fakerphp/faker", + "version": "v1.24.1", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1" + }, + "time": "2024-11-21T13:46:39+00:00" + }, + { + "name": "filp/whoops", + "version": "2.18.0", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e", + "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.0" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-03-15T12:00:00+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1" + }, + "time": "2020-07-09T08:09:16+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "f31f4980f52be17c4667f3eafe034e6826787db2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/f31f4980f52be17c4667f3eafe034e6826787db2", + "reference": "f31f4980f52be17c4667f3eafe034e6826787db2", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0|^12.0", + "illuminate/contracts": "^10.24|^11.0|^12.0", + "illuminate/log": "^10.24|^11.0|^12.0", + "illuminate/process": "^10.24|^11.0|^12.0", + "illuminate/support": "^10.24|^11.0|^12.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.0", + "laravel/pint": "^1.13", + "orchestra/testbench-core": "^8.13|^9.0|^10.0", + "pestphp/pest": "^2.20|^3.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0", + "phpstan/phpstan": "^1.10", + "symfony/var-dumper": "^6.3|^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2025-01-28T15:15:15+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.21.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "370772e7d9e9da087678a0edf2b11b6960e40558" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/370772e7d9e9da087678a0edf2b11b6960e40558", + "reference": "370772e7d9e9da087678a0edf2b11b6960e40558", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.72.0", + "illuminate/view": "^11.44.2", + "larastan/larastan": "^3.2.0", + "laravel-zero/framework": "^11.36.1", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3", + "pestphp/pest": "^2.36.0" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2025-03-14T22:31:42+00:00" + }, + { + "name": "laravel/sail", + "version": "v1.41.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/sail.git", + "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sail/zipball/fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec", + "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0", + "symfony/yaml": "^6.0|^7.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "phpstan/phpstan": "^1.10" + }, + "bin": [ + "bin/sail" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sail\\SailServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Docker files for running a basic Laravel application.", + "keywords": [ + "docker", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/sail/issues", + "source": "https://github.com/laravel/sail" + }, + "time": "2025-01-24T15:45:36+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-02-12T12:17:51+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.7.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "586cb8181a257a2152b6a855ca8d9598878a1a26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/586cb8181a257a2152b6a855ca8d9598878a1a26", + "reference": "586cb8181a257a2152b6a855ca8d9598878a1a26", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.17.0", + "nunomaduro/termwind": "^2.3.0", + "php": "^8.2.0", + "symfony/console": "^7.2.1" + }, + "conflict": { + "laravel/framework": "<11.39.1 || >=13.0.0", + "phpunit/phpunit": "<11.5.3 || >=12.0.0" + }, + "require-dev": { + "larastan/larastan": "^2.10.0", + "laravel/framework": "^11.44.2", + "laravel/pint": "^1.21.2", + "laravel/sail": "^1.41.0", + "laravel/sanctum": "^4.0.8", + "laravel/tinker": "^2.10.1", + "orchestra/testbench-core": "^9.12.0", + "pestphp/pest": "^3.7.4", + "sebastian/environment": "^6.1.0 || ^7.2.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-03-14T22:37:40+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.0", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.2" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-25T13:26:39+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-27T05:02:59+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.14", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "9d6046153c2893b521784069e6b5249ce7d2acae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9d6046153c2893b521784069e6b5249ce7d2acae", + "reference": "9d6046153c2893b521784069e6b5249ce7d2acae", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.9", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.1", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.0", + "sebastian/exporter": "^6.3.0", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.2", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.14" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-03-19T13:45:48+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-07T06:57:01+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:54:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-05T09:17:50+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:10:34+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-18T13:35:50+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ac238f173df0c9c1120f862d0f599e17535a87ec", + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-07T12:55:42+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.2" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/TA_API/config/app.php b/TA_API/config/app.php new file mode 100644 index 0000000..333ab82 --- /dev/null +++ b/TA_API/config/app.php @@ -0,0 +1,189 @@ + env('APP_NAME', 'Laravel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | the application so that it's available within Artisan commands. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Frontend URL + |-------------------------------------------------------------------------- + | + | This URL is used to generate links to the frontend application for + | features like email verification and password reset. + | + */ + + 'frontend_url' => env('FRONTEND_URL', 'http://localhost:3000'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. The timezone + | is set to "UTC" by default as it is suitable for most use cases. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by Laravel's translation / localization methods. This option can be + | set to any locale for which you plan to have translation strings. + | + */ + + 'locale' => env('APP_LOCALE', 'en'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), + + 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. + | + */ + + 'cipher' => 'AES-256-CBC', + + 'key' => env('APP_KEY'), + + 'previous_keys' => [ + ...array_filter( + explode(',', env('APP_PREVIOUS_KEYS', '')) + ), + ], + + /* + |-------------------------------------------------------------------------- + | Maintenance Mode Driver + |-------------------------------------------------------------------------- + | + | These configuration options determine the driver used to determine and + | manage Laravel's "maintenance mode" status. The "cache" driver will + | allow maintenance mode to be controlled across multiple machines. + | + | Supported drivers: "file", "cache" + | + */ + + 'maintenance' => [ + 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), + 'store' => env('APP_MAINTENANCE_STORE', 'database'), + ], + + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + 'providers' => [ + /* + * Laravel Framework Service Providers... + */ + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Broadcasting\BroadcastServiceProvider::class, + Illuminate\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Pipeline\PipelineServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, + + /* + * Package Service Providers... + */ + + /* + * Application Service Providers... + */ + App\Providers\AppServiceProvider::class, + App\Providers\AuthServiceProvider::class, + App\Providers\EventServiceProvider::class, + App\Providers\RouteServiceProvider::class, + ], + +]; diff --git a/TA_API/config/auth.php b/TA_API/config/auth.php new file mode 100644 index 0000000..0ba5d5d --- /dev/null +++ b/TA_API/config/auth.php @@ -0,0 +1,115 @@ + [ + 'guard' => env('AUTH_GUARD', 'web'), + 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | which utilizes session storage plus the Eloquent user provider. + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | Supported: "session" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + ], + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | If you have multiple user tables or models you may configure multiple + | providers to represent the model / table. These providers may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => env('AUTH_MODEL', App\Models\User::class), + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | These configuration options specify the behavior of Laravel's password + | reset functionality, including the table utilized for token storage + | and the user provider that is invoked to actually retrieve users. + | + | The expiry time is the number of minutes that each reset token will be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + | The throttle setting is the number of seconds a user must wait before + | generating more password reset tokens. This prevents the user from + | quickly generating a very large amount of password reset tokens. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), + 'expire' => 60, + 'throttle' => 60, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Password Confirmation Timeout + |-------------------------------------------------------------------------- + | + | Here you may define the amount of seconds before a password confirmation + | window expires and users are asked to re-enter their password via the + | confirmation screen. By default, the timeout lasts for three hours. + | + */ + + 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), + +]; diff --git a/TA_API/config/cache.php b/TA_API/config/cache.php new file mode 100644 index 0000000..925f7d2 --- /dev/null +++ b/TA_API/config/cache.php @@ -0,0 +1,108 @@ + env('CACHE_STORE', 'database'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + | Supported drivers: "array", "database", "file", "memcached", + | "redis", "dynamodb", "octane", "null" + | + */ + + 'stores' => [ + + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_CACHE_CONNECTION'), + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), + 'lock_table' => env('DB_CACHE_LOCK_TABLE'), + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + 'lock_path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), + 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), + ], + + 'dynamodb' => [ + 'driver' => 'dynamodb', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), + 'endpoint' => env('DYNAMODB_ENDPOINT'), + ], + + 'octane' => [ + 'driver' => 'octane', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing the APC, database, memcached, Redis, and DynamoDB cache + | stores, there might be other applications using the same cache. For + | that reason, you may prefix every cache key to avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), + +]; diff --git a/TA_API/config/database.php b/TA_API/config/database.php new file mode 100644 index 0000000..68e85cc --- /dev/null +++ b/TA_API/config/database.php @@ -0,0 +1,177 @@ + env('DB_CONNECTION', 'mysql'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Below are all of the database connections defined for your application. + | An example configuration is provided for each database system which + | is supported by Laravel. You're free to add / remove connections. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DB_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + 'busy_timeout' => null, + 'journal_mode' => null, + 'synchronous' => null, + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'mariadb' => [ + 'driver' => 'mariadb', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + // 'encrypt' => env('DB_ENCRYPT', 'yes'), + // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run on the database. + | + */ + + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as Memcached. You may define your connection settings here. + | + */ + + 'redis' => [ + + 'client' => env('REDIS_CLIENT', 'phpredis'), + + 'options' => [ + 'cluster' => env('REDIS_CLUSTER', 'redis'), + 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), + 'persistent' => env('REDIS_PERSISTENT', false), + ], + + 'default' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_DB', '0'), + ], + + 'cache' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_CACHE_DB', '1'), + ], + + ], + +]; diff --git a/TA_API/config/filesystems.php b/TA_API/config/filesystems.php new file mode 100644 index 0000000..3d671bd --- /dev/null +++ b/TA_API/config/filesystems.php @@ -0,0 +1,80 @@ + env('FILESYSTEM_DISK', 'local'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Below you may configure as many filesystem disks as necessary, and you + | may even configure multiple disks for the same driver. Examples for + | most supported storage drivers are configured here for reference. + | + | Supported drivers: "local", "ftp", "sftp", "s3" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app/private'), + 'serve' => true, + 'throw' => false, + 'report' => false, + ], + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', + 'throw' => false, + 'report' => false, + ], + + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + 'url' => env('AWS_URL'), + 'endpoint' => env('AWS_ENDPOINT'), + 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), + 'throw' => false, + 'report' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Symbolic Links + |-------------------------------------------------------------------------- + | + | Here you may configure the symbolic links that will be created when the + | `storage:link` Artisan command is executed. The array keys should be + | the locations of the links and the values should be their targets. + | + */ + + 'links' => [ + public_path('storage') => storage_path('app/public'), + ], + +]; diff --git a/TA_API/config/ide-helper.php b/TA_API/config/ide-helper.php new file mode 100644 index 0000000..1500783 --- /dev/null +++ b/TA_API/config/ide-helper.php @@ -0,0 +1,352 @@ + '_ide_helper.php', + + /* + |-------------------------------------------------------------------------- + | Models filename + |-------------------------------------------------------------------------- + | + | The default filename for the models helper file. + | + */ + + 'models_filename' => '_ide_helper_models.php', + + /* + |-------------------------------------------------------------------------- + | PhpStorm meta filename + |-------------------------------------------------------------------------- + | + | PhpStorm also supports the directory `.phpstorm.meta.php/` with arbitrary + | files in it, should you need additional files for your project; e.g. + | `.phpstorm.meta.php/laravel_ide_Helper.php'. + | + */ + 'meta_filename' => '.phpstorm.meta.php', + + /* + |-------------------------------------------------------------------------- + | Fluent helpers + |-------------------------------------------------------------------------- + | + | Set to true to generate commonly used Fluent methods. + | + */ + + 'include_fluent' => false, + + /* + |-------------------------------------------------------------------------- + | Factory builders + |-------------------------------------------------------------------------- + | + | Set to true to generate factory generators for better factory() + | method auto-completion. + | + | Deprecated for Laravel 8 or latest. + | + */ + + 'include_factory_builders' => false, + + /* + |-------------------------------------------------------------------------- + | Write model magic methods + |-------------------------------------------------------------------------- + | + | Set to false to disable write magic methods of model. + | + */ + + 'write_model_magic_where' => true, + + /* + |-------------------------------------------------------------------------- + | Write model external Eloquent builder methods + |-------------------------------------------------------------------------- + | + | Set to false to disable write external Eloquent builder methods. + | + */ + + 'write_model_external_builder_methods' => true, + + /* + |-------------------------------------------------------------------------- + | Write model relation count properties + |-------------------------------------------------------------------------- + | + | Set to false to disable writing of relation count properties to model DocBlocks. + | + */ + + 'write_model_relation_count_properties' => true, + + /* + |-------------------------------------------------------------------------- + | Write Eloquent model mixins + |-------------------------------------------------------------------------- + | + | This will add the necessary DocBlock mixins to the model class + | contained in the Laravel framework. This helps the IDE with + | auto-completion. + | + | Please be aware that this setting changes a file within the /vendor directory. + | + */ + + 'write_eloquent_model_mixins' => false, + + /* + |-------------------------------------------------------------------------- + | Helper files to include + |-------------------------------------------------------------------------- + | + | Include helper files. By default not included, but can be toggled with the + | -- helpers (-H) option. Extra helper files can be included. + | + */ + + 'include_helpers' => false, + + 'helper_files' => [ + base_path() . '/vendor/laravel/framework/src/Illuminate/Support/helpers.php', + base_path() . '/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php', + ], + + /* + |-------------------------------------------------------------------------- + | Model locations to include + |-------------------------------------------------------------------------- + | + | Define in which directories the ide-helper:models command should look + | for models. + | + | glob patterns are supported to easier reach models in sub-directories, + | e.g. `app/Services/* /Models` (without the space). + | + */ + + 'model_locations' => [ + 'app', + ], + + /* + |-------------------------------------------------------------------------- + | Models to ignore + |-------------------------------------------------------------------------- + | + | Define which models should be ignored. + | + */ + + 'ignored_models' => [ + // App\MyModel::class, + ], + + /* + |-------------------------------------------------------------------------- + | Models hooks + |-------------------------------------------------------------------------- + | + | Define which hook classes you want to run for models to add custom information. + | + | Hooks should implement Barryvdh\LaravelIdeHelper\Contracts\ModelHookInterface. + | + */ + + 'model_hooks' => [ + // App\Support\IdeHelper\MyModelHook::class + ], + + /* + |-------------------------------------------------------------------------- + | Extra classes + |-------------------------------------------------------------------------- + | + | These implementations are not really extended, but called with magic functions. + | + */ + + 'extra' => [ + 'Eloquent' => ['Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'], + 'Session' => ['Illuminate\Session\Store'], + ], + + 'magic' => [], + + /* + |-------------------------------------------------------------------------- + | Interface implementations + |-------------------------------------------------------------------------- + | + | These interfaces will be replaced with the implementing class. Some interfaces + | are detected by the helpers, others can be listed below. + | + */ + + 'interfaces' => [ + // App\MyInterface::class => App\MyImplementation::class, + ], + + /* + |-------------------------------------------------------------------------- + | Support for camel cased models + |-------------------------------------------------------------------------- + | + | There are some Laravel packages (such as Eloquence) that allow for accessing + | Eloquent model properties via camel case, instead of snake case. + | + | Enabling this option will support these packages by saving all model + | properties as camel case, instead of snake case. + | + | For example, normally you would see this: + | + | * @property \Illuminate\Support\Carbon $created_at + | * @property \Illuminate\Support\Carbon $updated_at + | + | With this enabled, the properties will be this: + | + | * @property \Illuminate\Support\Carbon $createdAt + | * @property \Illuminate\Support\Carbon $updatedAt + | + | Note, it is currently an all-or-nothing option. + | + */ + 'model_camel_case_properties' => false, + + /* + |-------------------------------------------------------------------------- + | Property casts + |-------------------------------------------------------------------------- + | + | Cast the given "real type" to the given "type". + | + */ + 'type_overrides' => [ + 'integer' => 'int', + 'boolean' => 'bool', + ], + + /* + |-------------------------------------------------------------------------- + | Include DocBlocks from classes + |-------------------------------------------------------------------------- + | + | Include DocBlocks from classes to allow additional code inspection for + | magic methods and properties. + | + */ + 'include_class_docblocks' => false, + + /* + |-------------------------------------------------------------------------- + | Force FQN usage + |-------------------------------------------------------------------------- + | + | Use the fully qualified (class) name in DocBlocks, + | even if the class exists in the same namespace + | or there is an import (use className) of the class. + | + */ + 'force_fqn' => false, + + /* + |-------------------------------------------------------------------------- + | Use generics syntax + |-------------------------------------------------------------------------- + | + | Use generics syntax within DocBlocks, + | e.g. `Collection` instead of `Collection|User[]`. + | + */ + 'use_generics_annotations' => true, + + /* + |-------------------------------------------------------------------------- + | Additional relation types + |-------------------------------------------------------------------------- + | + | Sometimes it's needed to create custom relation types. The key of the array + | is the relationship method name. The value of the array is the fully-qualified + | class name of the relationship, e.g. `'relationName' => RelationShipClass::class`. + | + */ + 'additional_relation_types' => [], + + /* + |-------------------------------------------------------------------------- + | Additional relation return types + |-------------------------------------------------------------------------- + | + | When using custom relation types its possible for the class name to not contain + | the proper return type of the relation. The key of the array is the relationship + | method name. The value of the array is the return type of the relation ('many' + | or 'morphTo'). + | e.g. `'relationName' => 'many'`. + | + */ + 'additional_relation_return_types' => [], + + /* + |-------------------------------------------------------------------------- + | Enforce nullable Eloquent relationships on not null columns + |-------------------------------------------------------------------------- + | + | When set to true (default), this option enforces nullable Eloquent relationships. + | However, in cases where the application logic ensures the presence of related + | records it may be desirable to set this option to false to avoid unwanted null warnings. + | + | Default: true + | A not null column with no foreign key constraint will have a "nullable" relationship. + | * @property int $not_null_column_with_no_foreign_key_constraint + | * @property-read BelongsToVariation|null $notNullColumnWithNoForeignKeyConstraint + | + | Option: false + | A not null column with no foreign key constraint will have a "not nullable" relationship. + | * @property int $not_null_column_with_no_foreign_key_constraint + | * @property-read BelongsToVariation $notNullColumnWithNoForeignKeyConstraint + | + */ + + 'enforce_nullable_relationships' => true, + + /* + |-------------------------------------------------------------------------- + | Run artisan commands after migrations to generate model helpers + |-------------------------------------------------------------------------- + | + | The specified commands should run after migrations are finished running. + | + */ + 'post_migrate' => [ + // 'ide-helper:models --nowrite', + ], + + /* + |-------------------------------------------------------------------------- + | Macroable Traits + |-------------------------------------------------------------------------- + | + | Define which traits should be considered capable of adding Macro. + | You can add any custom trait that behaves like the original Laravel one. + | + */ + 'macroable_traits' => [ + Filament\Support\Concerns\Macroable::class, + Spatie\Macroable\Macroable::class, + ], + +]; diff --git a/TA_API/config/logging.php b/TA_API/config/logging.php new file mode 100644 index 0000000..1345f6f --- /dev/null +++ b/TA_API/config/logging.php @@ -0,0 +1,132 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Deprecations Log Channel + |-------------------------------------------------------------------------- + | + | This option controls the log channel that should be used to log warnings + | regarding deprecated PHP and library features. This allows you to get + | your application ready for upcoming major versions of dependencies. + | + */ + + 'deprecations' => [ + 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), + 'trace' => env('LOG_DEPRECATIONS_TRACE', false), + ], + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Laravel + | utilizes the Monolog PHP logging library, which includes a variety + | of powerful log handlers and formatters that you're free to use. + | + | Available drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", "custom", "stack" + | + */ + + 'channels' => [ + + 'stack' => [ + 'driver' => 'stack', + 'channels' => explode(',', env('LOG_STACK', 'single')), + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => env('LOG_DAILY_DAYS', 14), + 'replace_placeholders' => true, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), + 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), + 'level' => env('LOG_LEVEL', 'critical'), + 'replace_placeholders' => true, + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => StreamHandler::class, + 'handler_with' => [ + 'stream' => 'php://stderr', + ], + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), + 'replace_placeholders' => true, + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/laravel.log'), + ], + + ], + +]; diff --git a/TA_API/config/mail.php b/TA_API/config/mail.php new file mode 100644 index 0000000..756305b --- /dev/null +++ b/TA_API/config/mail.php @@ -0,0 +1,116 @@ + env('MAIL_MAILER', 'log'), + + /* + |-------------------------------------------------------------------------- + | Mailer Configurations + |-------------------------------------------------------------------------- + | + | Here you may configure all of the mailers used by your application plus + | their respective settings. Several examples have been configured for + | you and you are free to add your own as your application requires. + | + | Laravel supports a variety of mail "transport" drivers that can be used + | when delivering an email. You may specify which one you're using for + | your mailers below. You may also add additional mailers if needed. + | + | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", + | "postmark", "resend", "log", "array", + | "failover", "roundrobin" + | + */ + + 'mailers' => [ + + 'smtp' => [ + 'transport' => 'smtp', + 'scheme' => env('MAIL_SCHEME'), + 'url' => env('MAIL_URL'), + 'host' => env('MAIL_HOST', '127.0.0.1'), + 'port' => env('MAIL_PORT', 2525), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'postmark' => [ + 'transport' => 'postmark', + // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), + // 'client' => [ + // 'timeout' => 5, + // ], + ], + + 'resend' => [ + 'transport' => 'resend', + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), + ], + + 'log' => [ + 'transport' => 'log', + 'channel' => env('MAIL_LOG_CHANNEL'), + ], + + 'array' => [ + 'transport' => 'array', + ], + + 'failover' => [ + 'transport' => 'failover', + 'mailers' => [ + 'smtp', + 'log', + ], + ], + + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'ses', + 'postmark', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all emails sent by your application to be sent from + | the same address. Here you may specify a name and address that is + | used globally for all emails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + +]; diff --git a/TA_API/config/queue.php b/TA_API/config/queue.php new file mode 100644 index 0000000..116bd8d --- /dev/null +++ b/TA_API/config/queue.php @@ -0,0 +1,112 @@ + env('QUEUE_CONNECTION', 'database'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Laravel. You're also free to add more. + | + | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'after_commit' => false, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), + 'queue' => env('BEANSTALKD_QUEUE', 'default'), + 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), + 'block_for' => 0, + 'after_commit' => false, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'default'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'after_commit' => false, + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), + 'block_for' => null, + 'after_commit' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'job_batches', + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control how and where failed jobs are stored. Laravel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/TA_API/config/sanctum.php b/TA_API/config/sanctum.php new file mode 100644 index 0000000..764a82f --- /dev/null +++ b/TA_API/config/sanctum.php @@ -0,0 +1,83 @@ + explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( + '%s%s', + 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', + Sanctum::currentApplicationUrlWithPort() + ))), + + /* + |-------------------------------------------------------------------------- + | Sanctum Guards + |-------------------------------------------------------------------------- + | + | This array contains the authentication guards that will be checked when + | Sanctum is trying to authenticate a request. If none of these guards + | are able to authenticate the request, Sanctum will use the bearer + | token that's present on an incoming request for authentication. + | + */ + + 'guard' => ['web'], + + /* + |-------------------------------------------------------------------------- + | Expiration Minutes + |-------------------------------------------------------------------------- + | + | This value controls the number of minutes until an issued token will be + | considered expired. This will override any values set in the token's + | "expires_at" attribute, but first-party sessions are not affected. + | + */ + + 'expiration' => null, + + /* + |-------------------------------------------------------------------------- + | Token Prefix + |-------------------------------------------------------------------------- + | + | Sanctum can prefix new tokens in order to take advantage of numerous + | security scanning initiatives maintained by open source platforms + | that notify developers if they commit tokens into repositories. + | + | See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning + | + */ + + 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Sanctum Middleware + |-------------------------------------------------------------------------- + | + | When authenticating your first-party SPA with Sanctum you may need to + | customize some of the middleware Sanctum uses while processing the + | request. You may change the middleware listed below as required. + | + */ + + 'middleware' => [ + 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, + 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, + 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, + ], + +]; diff --git a/TA_API/config/services.php b/TA_API/config/services.php new file mode 100644 index 0000000..27a3617 --- /dev/null +++ b/TA_API/config/services.php @@ -0,0 +1,38 @@ + [ + 'token' => env('POSTMARK_TOKEN'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'resend' => [ + 'key' => env('RESEND_KEY'), + ], + + 'slack' => [ + 'notifications' => [ + 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), + 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), + ], + ], + +]; diff --git a/TA_API/config/session.php b/TA_API/config/session.php new file mode 100644 index 0000000..ba0aa60 --- /dev/null +++ b/TA_API/config/session.php @@ -0,0 +1,217 @@ + env('SESSION_DRIVER', 'database'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to expire immediately when the browser is closed then you may + | indicate that via the expire_on_close configuration option. + | + */ + + 'lifetime' => (int) env('SESSION_LIFETIME', 120), + + 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it's stored. All encryption is performed + | automatically by Laravel and you may use the session like normal. + | + */ + + 'encrypt' => env('SESSION_ENCRYPT', false), + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When utilizing the "file" session driver, the session files are placed + | on disk. The default storage location is defined here; however, you + | are free to provide another location where they should be stored. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => env('SESSION_CONNECTION'), + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table to + | be used to store sessions. Of course, a sensible default is defined + | for you; however, you're welcome to change this to another table. + | + */ + + 'table' => env('SESSION_TABLE', 'sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using one of the framework's cache driven session backends, you may + | define the cache store which should be used to store the session data + | between requests. This must match one of your defined cache stores. + | + | Affects: "apc", "dynamodb", "memcached", "redis" + | + */ + + 'store' => env('SESSION_STORE'), + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the session cookie that is created by + | the framework. Typically, you should not need to change this value + | since doing so does not grant a meaningful security improvement. + | + */ + + 'cookie' => env( + 'SESSION_COOKIE', + Str::slug(env('APP_NAME', 'laravel'), '_').'_session' + ), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application, but you're free to change this when necessary. + | + */ + + 'path' => env('SESSION_PATH', '/'), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | This value determines the domain and subdomains the session cookie is + | available to. By default, the cookie will be available to the root + | domain and all subdomains. Typically, this shouldn't be changed. + | + */ + + 'domain' => env('SESSION_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you when it can't be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE'), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. It's unlikely you should disable this option. + | + */ + + 'http_only' => env('SESSION_HTTP_ONLY', true), + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | will set this value to "lax" to permit secure cross-site requests. + | + | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value + | + | Supported: "lax", "strict", "none", null + | + */ + + 'same_site' => env('SESSION_SAME_SITE', 'lax'), + + /* + |-------------------------------------------------------------------------- + | Partitioned Cookies + |-------------------------------------------------------------------------- + | + | Setting this value to true will tie the cookie to the top-level site for + | a cross-site context. Partitioned cookies are accepted by the browser + | when flagged "secure" and the Same-Site attribute is set to "none". + | + */ + + 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), + +]; diff --git a/TA_API/database/.gitignore b/TA_API/database/.gitignore new file mode 100644 index 0000000..9b19b93 --- /dev/null +++ b/TA_API/database/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/TA_API/database/factories/UserFactory.php b/TA_API/database/factories/UserFactory.php new file mode 100644 index 0000000..584104c --- /dev/null +++ b/TA_API/database/factories/UserFactory.php @@ -0,0 +1,44 @@ + + */ +class UserFactory extends Factory +{ + /** + * The current password being used by the factory. + */ + protected static ?string $password; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'name' => fake()->name(), + 'email' => fake()->unique()->safeEmail(), + 'email_verified_at' => now(), + 'password' => static::$password ??= Hash::make('password'), + 'remember_token' => Str::random(10), + ]; + } + + /** + * Indicate that the model's email address should be unverified. + */ + public function unverified(): static + { + return $this->state(fn (array $attributes) => [ + 'email_verified_at' => null, + ]); + } +} diff --git a/TA_API/database/migrations/0001_01_01_000001_create_cache_table.php b/TA_API/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..b9c106b --- /dev/null +++ b/TA_API/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration'); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/TA_API/database/migrations/0001_01_01_000002_create_jobs_table.php b/TA_API/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..425e705 --- /dev/null +++ b/TA_API/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,57 @@ +id(); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + + Schema::create('job_batches', function (Blueprint $table) { + $table->string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->longText('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->string('uuid')->unique(); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->longText('exception'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + Schema::dropIfExists('job_batches'); + Schema::dropIfExists('failed_jobs'); + } +}; diff --git a/TA_API/database/migrations/2014_10_12_000000_create_users_table.php b/TA_API/database/migrations/2014_10_12_000000_create_users_table.php new file mode 100644 index 0000000..e66cd00 --- /dev/null +++ b/TA_API/database/migrations/2014_10_12_000000_create_users_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->string('password'); + $table->string('role'); // 'admin', 'penjahit', 'pelanggan' + $table->string('phone_number')->nullable(); + $table->text('address')->nullable(); + $table->text('shop_description')->nullable(); // Deskripsi toko untuk penjahit + $table->string('profile_photo')->nullable(); // Foto profil + $table->timestamp('email_verified_at')->nullable(); + $table->rememberToken(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_03_23_000000_create_tailor_services_table.php b/TA_API/database/migrations/2024_03_23_000000_create_tailor_services_table.php new file mode 100644 index 0000000..eab7e26 --- /dev/null +++ b/TA_API/database/migrations/2024_03_23_000000_create_tailor_services_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->string('name'); + $table->text('description'); + $table->decimal('price', 10, 2); + $table->string('category'); // Bawahan, Atasan, Terusan, Perbaikan + $table->integer('estimated_days')->default(1); // Estimasi waktu pengerjaan dalam hari + $table->boolean('is_available')->default(true); + $table->string('service_photo')->nullable(); // Foto contoh hasil jasa + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tailor_services'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_03_23_create_bookings_table.php b/TA_API/database/migrations/2024_03_23_create_bookings_table.php new file mode 100644 index 0000000..f89eda0 --- /dev/null +++ b/TA_API/database/migrations/2024_03_23_create_bookings_table.php @@ -0,0 +1,43 @@ +id(); + $table->foreignId('customer_id')->constrained('users')->onDelete('cascade'); + $table->foreignId('tailor_id')->constrained('users')->onDelete('cascade'); + $table->date('appointment_date'); + $table->time('appointment_time'); + $table->enum('service_type', ['Perbaikan', 'Jahit Baru']); + $table->enum('category', ['Atasan', 'Bawahan', 'Terusan']); + $table->string('design_photo')->nullable(); + $table->text('notes')->nullable(); + $table->enum('status', [ + 'reservasi', // Status awal saat booking dibuat + 'diproses', // Penjahit sudah menerima dan sedang mengerjakan + 'selesai', // Jahitan sudah selesai + 'dibatalkan' // Booking dibatalkan + ])->default('reservasi'); + $table->decimal('total_price', 10, 2)->nullable(); + $table->enum('payment_status', ['unpaid', 'paid'])->default('unpaid'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('bookings'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_03_23_create_tailor_ratings_table.php b/TA_API/database/migrations/2024_03_23_create_tailor_ratings_table.php new file mode 100644 index 0000000..f53fd4b --- /dev/null +++ b/TA_API/database/migrations/2024_03_23_create_tailor_ratings_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('booking_id')->constrained()->onDelete('cascade'); + $table->foreignId('customer_id')->constrained('users')->onDelete('cascade'); + $table->foreignId('tailor_id')->constrained('users')->onDelete('cascade'); + $table->decimal('rating', 2, 1); // Rating 0.0 - 5.0 + $table->text('review')->nullable(); + $table->timestamps(); + + // Satu customer hanya bisa memberikan satu rating per booking + $table->unique(['booking_id', 'customer_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tailor_ratings'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_03_23_create_tailor_specializations_table.php b/TA_API/database/migrations/2024_03_23_create_tailor_specializations_table.php new file mode 100644 index 0000000..abdcad9 --- /dev/null +++ b/TA_API/database/migrations/2024_03_23_create_tailor_specializations_table.php @@ -0,0 +1,50 @@ +id(); + $table->string('name'); + $table->string('icon')->nullable(); + $table->timestamps(); + }); + + // Pivot table untuk relasi many-to-many antara penjahit dan spesialisasi + Schema::create('tailor_specialization_user', function (Blueprint $table) { + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->foreignId('tailor_specialization_id')->constrained()->onDelete('cascade'); + $table->primary(['user_id', 'tailor_specialization_id']); + }); + + // Insert default specializations + DB::table('tailor_specializations')->insert([ + ['name' => 'Celana', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Rok', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Kemeja', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Seragam', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Jas Blazer', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Kebaya', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Gaun', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Gamis', 'created_at' => now(), 'updated_at' => now()], + ]); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tailor_specialization_user'); + Schema::dropIfExists('tailor_specializations'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_03_27_create_tailor_galleries_table.php b/TA_API/database/migrations/2024_03_27_create_tailor_galleries_table.php new file mode 100644 index 0000000..04e34ad --- /dev/null +++ b/TA_API/database/migrations/2024_03_27_create_tailor_galleries_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->string('photo'); + $table->string('title')->nullable(); + $table->text('description')->nullable(); + $table->string('category')->nullable(); // Misalnya: Baju Pesta, Kemeja, Celana, dll + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tailor_galleries'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_04_07_082735_add_completion_date_to_bookings_table.php b/TA_API/database/migrations/2024_04_07_082735_add_completion_date_to_bookings_table.php new file mode 100644 index 0000000..a89bc44 --- /dev/null +++ b/TA_API/database/migrations/2024_04_07_082735_add_completion_date_to_bookings_table.php @@ -0,0 +1,28 @@ +date('completion_date')->nullable()->after('total_price'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropColumn('completion_date'); + }); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_04_18_000000_create_password_resets_table.php b/TA_API/database/migrations/2024_04_18_000000_create_password_resets_table.php new file mode 100644 index 0000000..6ae2208 --- /dev/null +++ b/TA_API/database/migrations/2024_04_18_000000_create_password_resets_table.php @@ -0,0 +1,28 @@ +string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('password_resets'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_04_19_000000_add_payment_method_and_transaction_code_to_bookings.php b/TA_API/database/migrations/2024_04_19_000000_add_payment_method_and_transaction_code_to_bookings.php new file mode 100644 index 0000000..13c9508 --- /dev/null +++ b/TA_API/database/migrations/2024_04_19_000000_add_payment_method_and_transaction_code_to_bookings.php @@ -0,0 +1,30 @@ +enum('payment_method', ['tunai', 'transfer_bank', 'ewallet', 'qris'])->nullable()->after('payment_status'); + $table->string('transaction_code', 20)->nullable()->after('id')->unique(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropColumn('payment_method'); + $table->dropColumn('transaction_code'); + }); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_04_19_100000_change_payment_method_to_varchar.php b/TA_API/database/migrations/2024_04_19_100000_change_payment_method_to_varchar.php new file mode 100644 index 0000000..b415f51 --- /dev/null +++ b/TA_API/database/migrations/2024_04_19_100000_change_payment_method_to_varchar.php @@ -0,0 +1,41 @@ +dropColumn('payment_method'); + }); + + // Langkah 2: Tambahkan kolom baru dengan tipe varchar + Schema::table('bookings', function (Blueprint $table) { + $table->string('payment_method', 50)->nullable()->after('payment_status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Langkah 1: Drop kolom varchar payment_method + Schema::table('bookings', function (Blueprint $table) { + $table->dropColumn('payment_method'); + }); + + // Langkah 2: Kembalikan ke kolom enum + Schema::table('bookings', function (Blueprint $table) { + $table->enum('payment_method', ['tunai', 'transfer_bank', 'ewallet', 'qris'])->nullable()->after('payment_status'); + }); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_05_03_000001_create_wallets_table.php b/TA_API/database/migrations/2024_05_03_000001_create_wallets_table.php new file mode 100644 index 0000000..e6854d5 --- /dev/null +++ b/TA_API/database/migrations/2024_05_03_000001_create_wallets_table.php @@ -0,0 +1,24 @@ +id(); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->decimal('balance', 12, 2)->default(0); + $table->string('status')->default('active'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('wallets'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_05_03_000002_create_bank_accounts_table.php b/TA_API/database/migrations/2024_05_03_000002_create_bank_accounts_table.php new file mode 100644 index 0000000..5ec2321 --- /dev/null +++ b/TA_API/database/migrations/2024_05_03_000002_create_bank_accounts_table.php @@ -0,0 +1,28 @@ +id(); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->string('bank_name'); + $table->string('account_number'); + $table->string('account_holder_name'); + $table->string('status')->default('pending'); // pending, active, rejected + $table->text('rejection_reason')->nullable(); + $table->timestamp('verified_at')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('bank_accounts'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_05_03_000003_create_wallet_transactions_table.php b/TA_API/database/migrations/2024_05_03_000003_create_wallet_transactions_table.php new file mode 100644 index 0000000..6efdb45 --- /dev/null +++ b/TA_API/database/migrations/2024_05_03_000003_create_wallet_transactions_table.php @@ -0,0 +1,27 @@ +id(); + $table->foreignId('wallet_id')->constrained()->onDelete('cascade'); + $table->foreignId('booking_id')->nullable()->constrained()->onDelete('set null'); + $table->string('type'); // credit, debit + $table->decimal('amount', 12, 2); + $table->string('description'); + $table->string('status')->default('success'); // success, pending, failed + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('wallet_transactions'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2024_05_03_000004_create_withdrawals_table.php b/TA_API/database/migrations/2024_05_03_000004_create_withdrawals_table.php new file mode 100644 index 0000000..2c7dcbe --- /dev/null +++ b/TA_API/database/migrations/2024_05_03_000004_create_withdrawals_table.php @@ -0,0 +1,28 @@ +id(); + $table->foreignId('wallet_id')->constrained()->onDelete('cascade'); + $table->foreignId('bank_account_id')->constrained()->onDelete('cascade'); + $table->decimal('amount', 12, 2); + $table->string('status')->default('pending'); // pending, processing, completed, rejected + $table->text('rejection_reason')->nullable(); + $table->string('proof_of_payment')->nullable(); + $table->timestamp('processed_at')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('withdrawals'); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2025_03_23_110103_create_sessions_table.php b/TA_API/database/migrations/2025_03_23_110103_create_sessions_table.php new file mode 100644 index 0000000..f60625b --- /dev/null +++ b/TA_API/database/migrations/2025_03_23_110103_create_sessions_table.php @@ -0,0 +1,31 @@ +string('id')->primary(); + $table->foreignId('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sessions'); + } +}; diff --git a/TA_API/database/migrations/2025_03_23_112534_create_personal_access_tokens_table.php b/TA_API/database/migrations/2025_03_23_112534_create_personal_access_tokens_table.php new file mode 100644 index 0000000..e828ad8 --- /dev/null +++ b/TA_API/database/migrations/2025_03_23_112534_create_personal_access_tokens_table.php @@ -0,0 +1,33 @@ +id(); + $table->morphs('tokenable'); + $table->string('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamp('expires_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('personal_access_tokens'); + } +}; diff --git a/TA_API/database/migrations/2025_03_25_052708_add_measurements_to_bookings_table.php b/TA_API/database/migrations/2025_03_25_052708_add_measurements_to_bookings_table.php new file mode 100644 index 0000000..fe50de1 --- /dev/null +++ b/TA_API/database/migrations/2025_03_25_052708_add_measurements_to_bookings_table.php @@ -0,0 +1,28 @@ +json('measurements')->nullable()->after('payment_status'); + + // Tambahkan kolom lain yang diperlukan berdasarkan controller + $table->json('repair_details')->nullable()->after('measurements'); + $table->string('repair_photo')->nullable()->after('repair_details'); + $table->text('repair_notes')->nullable()->after('repair_photo'); + $table->string('completion_photo')->nullable()->after('repair_notes'); + $table->text('completion_notes')->nullable()->after('completion_photo'); + + // Tambahkan kolom untuk tracking waktu + $table->timestamp('accepted_at')->nullable()->after('completion_notes'); + $table->timestamp('rejected_at')->nullable()->after('accepted_at'); + $table->timestamp('completed_at')->nullable()->after('rejected_at'); + $table->text('rejection_reason')->nullable()->after('completed_at'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropColumn([ + 'measurements', + 'repair_details', + 'repair_photo', + 'repair_notes', + 'completion_photo', + 'completion_notes', + 'accepted_at', + 'rejected_at', + 'completed_at', + 'rejection_reason' + ]); + }); + } +}; diff --git a/TA_API/database/migrations/2025_03_25_061103_create_customer_specialization_table.php b/TA_API/database/migrations/2025_03_25_061103_create_customer_specialization_table.php new file mode 100644 index 0000000..6fd3eeb --- /dev/null +++ b/TA_API/database/migrations/2025_03_25_061103_create_customer_specialization_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->foreignId('tailor_specialization_id')->constrained()->onDelete('cascade'); + $table->timestamps(); + + // Tambahkan unique constraint untuk mencegah duplikasi + $table->unique(['user_id', 'tailor_specialization_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('customer_specialization'); + } +}; diff --git a/TA_API/database/migrations/2025_03_25_061144_add_coordinates_to_users_table.php b/TA_API/database/migrations/2025_03_25_061144_add_coordinates_to_users_table.php new file mode 100644 index 0000000..47d5f0c --- /dev/null +++ b/TA_API/database/migrations/2025_03_25_061144_add_coordinates_to_users_table.php @@ -0,0 +1,29 @@ +decimal('latitude', 10, 7)->nullable()->after('address'); + $table->decimal('longitude', 10, 7)->nullable()->after('latitude'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn(['latitude', 'longitude']); + }); + } +}; diff --git a/TA_API/database/migrations/2025_04_06_171929_add_category_to_tailor_specializations.php b/TA_API/database/migrations/2025_04_06_171929_add_category_to_tailor_specializations.php new file mode 100644 index 0000000..d428193 --- /dev/null +++ b/TA_API/database/migrations/2025_04_06_171929_add_category_to_tailor_specializations.php @@ -0,0 +1,28 @@ +string('category')->after('name')->default('Uncategorized'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('tailor_specializations', function (Blueprint $table) { + $table->dropColumn('category'); + }); + } +}; diff --git a/TA_API/database/migrations/2025_04_06_172929_add_photo_to_tailor_specializations.php b/TA_API/database/migrations/2025_04_06_172929_add_photo_to_tailor_specializations.php new file mode 100644 index 0000000..2c3f3ba --- /dev/null +++ b/TA_API/database/migrations/2025_04_06_172929_add_photo_to_tailor_specializations.php @@ -0,0 +1,28 @@ +string('photo')->nullable()->after('icon'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('tailor_specializations', function (Blueprint $table) { + $table->dropColumn('photo'); + }); + } +}; \ No newline at end of file diff --git a/TA_API/database/migrations/2025_04_06_185502_add_photo_to_tailor_specializations_table.php b/TA_API/database/migrations/2025_04_06_185502_add_photo_to_tailor_specializations_table.php new file mode 100644 index 0000000..4df44eb --- /dev/null +++ b/TA_API/database/migrations/2025_04_06_185502_add_photo_to_tailor_specializations_table.php @@ -0,0 +1,28 @@ +date('pickup_date')->nullable()->after('completed_at'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropColumn('pickup_date'); + }); + } +}; diff --git a/TA_API/database/migrations/2025_04_18_035606_create_password_reset_tokens_table.php b/TA_API/database/migrations/2025_04_18_035606_create_password_reset_tokens_table.php new file mode 100644 index 0000000..81a7229 --- /dev/null +++ b/TA_API/database/migrations/2025_04_18_035606_create_password_reset_tokens_table.php @@ -0,0 +1,28 @@ +string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('password_reset_tokens'); + } +}; diff --git a/TA_API/database/migrations/2025_05_02_030041_change_payment_status_column_in_bookings_table.php b/TA_API/database/migrations/2025_05_02_030041_change_payment_status_column_in_bookings_table.php new file mode 100644 index 0000000..48594ec --- /dev/null +++ b/TA_API/database/migrations/2025_05_02_030041_change_payment_status_column_in_bookings_table.php @@ -0,0 +1,40 @@ +dropColumn('payment_status'); + }); + + Schema::table('bookings', function (Blueprint $table) { + // Buat kolom baru payment_status dengan tipe varchar dan default 'unpaid' + $table->string('payment_status', 20)->default('unpaid')->after('total_price'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('bookings', function (Blueprint $table) { + // Hapus kolom string payment_status + $table->dropColumn('payment_status'); + }); + + Schema::table('bookings', function (Blueprint $table) { + // Kembalikan ke enum payment_status yang lama + $table->enum('payment_status', ['unpaid', 'paid'])->default('unpaid')->after('total_price'); + }); + } +}; diff --git a/TA_API/database/migrations/2025_05_02_031914_add_midtrans_fields_to_bookings_table.php b/TA_API/database/migrations/2025_05_02_031914_add_midtrans_fields_to_bookings_table.php new file mode 100644 index 0000000..3bf11ee --- /dev/null +++ b/TA_API/database/migrations/2025_05_02_031914_add_midtrans_fields_to_bookings_table.php @@ -0,0 +1,28 @@ +string('midtrans_snap_token')->nullable()->after('payment_method'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropColumn('midtrans_snap_token'); + }); + } +}; diff --git a/TA_API/database/seeders/AdminUserSeeder.php b/TA_API/database/seeders/AdminUserSeeder.php new file mode 100644 index 0000000..501634a --- /dev/null +++ b/TA_API/database/seeders/AdminUserSeeder.php @@ -0,0 +1,25 @@ + 'Admin Jahit', + 'email' => 'admin@jahit.com', + 'password' => Hash::make('admin123'), + 'role' => 'admin', + 'phone_number' => '081234567890', + 'address' => 'Jl. Admin No. 1' + ]); + } +} diff --git a/TA_API/database/seeders/DatabaseSeeder.php b/TA_API/database/seeders/DatabaseSeeder.php new file mode 100644 index 0000000..f9c0b60 --- /dev/null +++ b/TA_API/database/seeders/DatabaseSeeder.php @@ -0,0 +1,164 @@ +truncate(); + DB::table('tailor_specialization_user')->truncate(); + DB::table('tailor_specializations')->truncate(); + DB::table('users')->truncate(); + DB::statement('SET FOREIGN_KEY_CHECKS=1;'); + + // Seed Tailor Specializations first + $specializations = [ + ['name' => 'Baju Pria', 'category' => 'Pria', 'photo' => 'specializations/pria.jpg'], + ['name' => 'Baju Wanita', 'category' => 'Wanita', 'photo' => 'specializations/wanita.jpg'], + ['name' => 'Baju Anak', 'category' => 'Anak', 'photo' => 'specializations/anak.jpg'], + ['name' => 'Baju Muslim', 'category' => 'Muslim', 'photo' => 'specializations/muslim.jpg'], + ['name' => 'Baju Pesta', 'category' => 'Pesta', 'photo' => 'specializations/pesta.jpg'], + ['name' => 'Baju Olahraga', 'category' => 'Olahraga', 'photo' => 'specializations/olahraga.jpg'], + ]; + + foreach ($specializations as $spec) { + TailorSpecialization::create($spec); + } + + // Seed verified pelanggan + $pelanggan = [ + [ + 'name' => 'Ujang', + 'email' => 'ahmdrifai290@gmail.com', + 'password' => Hash::make('pelanggan123'), + 'role' => 'pelanggan', + 'phone_number' => '081234567890', + 'address' => 'Jl. Merdeka No. 123, Jakarta', + 'latitude' => -6.2088, + 'longitude' => 106.8456, + 'email_verified_at' => Carbon::now(), + 'preferred_specializations' => [1, 2] // Baju Pria dan Wanita + ], + [ + 'name' => 'Sarah Wijaya', + 'email' => 'sarah.wijaya@gmail.com', + 'password' => Hash::make('password123'), + 'role' => 'pelanggan', + 'phone_number' => '081234567891', + 'address' => 'Jl. Sudirman No. 45, Jakarta', + 'latitude' => -6.2088, + 'longitude' => 106.8456, + 'email_verified_at' => Carbon::now(), + 'preferred_specializations' => [2, 4] // Baju Wanita dan Muslim + ], + [ + 'name' => 'Budi Santoso', + 'email' => 'budi.santoso@gmail.com', + 'password' => Hash::make('password123'), + 'role' => 'pelanggan', + 'phone_number' => '081234567892', + 'address' => 'Jl. Gatot Subroto No. 67, Jakarta', + 'latitude' => -6.2088, + 'longitude' => 106.8456, + 'email_verified_at' => Carbon::now(), + 'preferred_specializations' => [1, 5] // Baju Pria dan Pesta + ] + ]; + + foreach ($pelanggan as $p) { + $user = User::create([ + 'name' => $p['name'], + 'email' => $p['email'], + 'password' => $p['password'], + 'role' => $p['role'], + 'phone_number' => $p['phone_number'], + 'address' => $p['address'], + 'latitude' => $p['latitude'], + 'longitude' => $p['longitude'], + 'email_verified_at' => $p['email_verified_at'] + ]); + + // Attach preferred specializations + $user->preferredSpecializations()->attach($p['preferred_specializations']); + } + + // Seed verified penjahit + $penjahit = [ + [ + 'name' => 'Asep Tailor', + 'email' => 'ahmdrifai2905@gmail.com', + 'password' => Hash::make('penjahit123'), + 'role' => 'penjahit', + 'phone_number' => '081234567893', + 'address' => 'Jl. Thamrin No. 89, Jakarta', + 'latitude' => -6.2088, + 'longitude' => 106.8456, + 'email_verified_at' => Carbon::now(), + 'shop_description' => 'Toko jahit profesional dengan pengalaman 10 tahun', + 'specializations' => [1, 2, 5] // Baju Pria, Wanita, dan Pesta + ], + [ + 'name' => 'Maya Fashion', + 'email' => 'maya.fashion@gmail.com', + 'password' => Hash::make('password123'), + 'role' => 'penjahit', + 'phone_number' => '081234567894', + 'address' => 'Jl. Asia Afrika No. 34, Bandung', + 'latitude' => -6.9175, + 'longitude' => 107.6191, + 'email_verified_at' => Carbon::now(), + 'shop_description' => 'Spesialis jahit baju wanita dan muslim', + 'specializations' => [2, 4] // Baju Wanita dan Muslim + ], + [ + 'name' => 'Rudi Custom Tailor', + 'email' => 'rudi.tailor@gmail.com', + 'password' => Hash::make('password123'), + 'role' => 'penjahit', + 'phone_number' => '081234567895', + 'address' => 'Jl. Veteran No. 56, Surabaya', + 'latitude' => -7.2575, + 'longitude' => 112.7521, + 'email_verified_at' => Carbon::now(), + 'shop_description' => 'Toko jahit custom untuk pria dan wanita', + 'specializations' => [1, 2, 3] // Baju Pria, Wanita, dan Anak + ] + ]; + + foreach ($penjahit as $p) { + $user = User::create([ + 'name' => $p['name'], + 'email' => $p['email'], + 'password' => $p['password'], + 'role' => $p['role'], + 'phone_number' => $p['phone_number'], + 'address' => $p['address'], + 'latitude' => $p['latitude'], + 'longitude' => $p['longitude'], + 'email_verified_at' => $p['email_verified_at'], + 'shop_description' => $p['shop_description'] + ]); + + // Attach specializations + $user->specializations()->attach($p['specializations']); + } + + $this->call([ + AdminUserSeeder::class + ]); + } +} diff --git a/TA_API/database/seeders/TailorSpecializationSeeder.php b/TA_API/database/seeders/TailorSpecializationSeeder.php new file mode 100644 index 0000000..58d89a7 --- /dev/null +++ b/TA_API/database/seeders/TailorSpecializationSeeder.php @@ -0,0 +1,40 @@ +truncate(); + + // Hapus data spesialisasi + DB::statement('SET FOREIGN_KEY_CHECKS=0;'); + DB::table('tailor_specializations')->truncate(); + DB::statement('SET FOREIGN_KEY_CHECKS=1;'); + + $specializations = [ + // Gaya Busana + ['name' => 'Casual', 'category' => 'Gaya Busana'], + ['name' => 'Formal', 'category' => 'Gaya Busana'], + ['name' => 'Tradisional', 'category' => 'Gaya Busana'], + ['name' => 'Modern', 'category' => 'Gaya Busana'], + + // Jenis Layanan + ['name' => 'Jahit Baru', 'category' => 'Jenis Layanan'], + ['name' => 'Perbaikan', 'category' => 'Jenis Layanan'], + ['name' => 'Design/Custom', 'category' => 'Jenis Layanan'], + + // Hiasan Busana + ['name' => 'Border', 'category' => 'Hiasan Busana'], + ['name' => 'Payet', 'category' => 'Hiasan Busana'], + ['name' => 'Sulam', 'category' => 'Hiasan Busana'] + ]; + + DB::table('tailor_specializations')->insert($specializations); + } +} \ No newline at end of file diff --git a/TA_API/docs/wallet-api.md b/TA_API/docs/wallet-api.md new file mode 100644 index 0000000..271e9f8 --- /dev/null +++ b/TA_API/docs/wallet-api.md @@ -0,0 +1,483 @@ +# Wallet & Withdrawal API Documentation + +## Table of Contents +1. [Midtrans Payment](#midtrans-payment) +2. [Wallet Management](#wallet-management) +3. [Bank Account Management](#bank-account-management) +4. [Withdrawal Management](#withdrawal-management) +5. [Admin Withdrawal Management](#admin-withdrawal-management) + +## Midtrans Payment + +### Initiate Midtrans Payment +```http +POST /api/bookings/{booking}/midtrans/pay +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "snap_token": "66e4fa55-fdac-4ef9-91b5-733b97d1b862", + "redirect_url": "https://app.sandbox.midtrans.com/snap/v2/vtweb/66e4fa55-fdac-4ef9-91b5-733b97d1b862", + "booking": { + "id": 1, + "transaction_code": "TRX-20240503-A1B2C3", + "total_price": 150000, + "status": "selesai" + } + }, + "message": "Token pembayaran berhasil dibuat" +} +``` + +### Check Payment Status +```http +GET /api/bookings/{booking}/payment-status +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "booking_id": 1, + "transaction_code": "TRX-20240503-A1B2C3", + "payment_status": "pending", + "payment_method": "bank_transfer", + "total_price": 150000, + "status": "selesai", + "midtrans_snap_token": "66e4fa55-fdac-4ef9-91b5-733b97d1b862" + }, + "message": "Status pembayaran berhasil diambil" +} +``` + +### Manual Check and Update Payment Status +```http +POST /api/bookings/{booking}/payment-status/check +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "booking_id": 1, + "transaction_code": "TRX-20240503-A1B2C3", + "payment_status": "paid", + "payment_method": "bank_transfer", + "total_price": 150000, + "status": "selesai", + "midtrans_status": "settlement", + "midtrans_snap_token": "66e4fa55-fdac-4ef9-91b5-733b97d1b862" + }, + "message": "Status pembayaran berhasil diperbarui" +} +``` + +## Wallet Management + +### Get Wallet Information +```http +GET /api/wallet +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "balance": 1000000.00, + "pending_withdrawals": 300000.00, + "available_balance": 700000.00, + "transactions": [ + { + "id": 1, + "type": "credit", + "amount": 500000.00, + "description": "Pembayaran booking #TRX-001", + "status": "success", + "created_at": "2024-05-03T10:00:00.000000Z", + "booking": { + "id": 1, + "transaction_code": "TRX-001", + "service_type": "jahit", + "category": "baju" + } + } + ] + }, + "message": "Wallet information retrieved successfully" +} +``` + +## Bank Account Management + +### Register Bank Account +```http +POST /api/bank-accounts +``` + +**Headers:** +``` +Authorization: Bearer {token} +Content-Type: application/json +``` + +**Request Body:** +```json +{ + "bank_name": "BCA", + "account_number": "1234567890", + "account_holder_name": "John Doe" +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "id": 1, + "bank_name": "BCA", + "account_number": "1234567890", + "account_holder_name": "John Doe", + "status": "pending", + "created_at": "2024-05-03T10:00:00.000000Z" + }, + "message": "Bank account registered successfully" +} +``` + +### Verify Bank Account (Admin Only) +```http +POST /api/admin/bank-accounts/{bankAccount}/verify +``` + +**Headers:** +``` +Authorization: Bearer {token} +Content-Type: application/json +``` + +**Request Body:** +```json +{ + "status": "active", + "rejection_reason": null +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "id": 1, + "bank_name": "BCA", + "account_number": "1234567890", + "account_holder_name": "John Doe", + "status": "active", + "verified_at": "2024-05-03T10:00:00.000000Z", + "updated_at": "2024-05-03T10:00:00.000000Z" + }, + "message": "Bank account verification completed" +} +``` + +## Withdrawal Management + +### Request Withdrawal +```http +POST /api/withdrawals +``` + +**Headers:** +``` +Authorization: Bearer {token} +Content-Type: application/json +``` + +**Request Body:** +```json +{ + "bank_account_id": 1, + "amount": 500000 +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "withdrawal": { + "id": 1, + "wallet_id": 1, + "bank_account_id": 1, + "amount": 500000.00, + "status": "pending", + "created_at": "2024-05-03T10:00:00.000000Z" + }, + "wallet": { + "balance": 1000000.00, + "pending_withdrawals": 500000.00, + "available_balance": 500000.00 + } + }, + "message": "Withdrawal request submitted successfully" +} +``` + +**Error Response - Insufficient Balance:** +```json +{ + "success": false, + "data": { + "balance": 1000000.00, + "pending_withdrawals": 800000.00, + "available_balance": 200000.00, + "requested_amount": 500000.00 + }, + "message": "Insufficient available balance." +} +``` + +### Get Withdrawal History +```http +GET /api/withdrawals +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Query Parameters:** +- `status` (optional) - Filter by withdrawal status. Allowed values: "pending", "processing", "completed", "rejected" + +**Response:** +```json +{ + "success": true, + "data": [ + { + "id": 1, + "amount": 500000.00, + "status": "completed", + "created_at": "2024-05-03T10:00:00.000000Z", + "processed_at": "2024-05-03T11:00:00.000000Z", + "bank_account": { + "bank_name": "BCA", + "account_number": "1234567890", + "account_holder_name": "John Doe" + } + } + ], + "message": "Withdrawal history retrieved successfully" +} +``` + +## Admin Withdrawal Management + +### Get Pending Withdrawals +```http +GET /api/admin/withdrawals/pending +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Response:** +```json +{ + "success": true, + "data": [ + { + "id": 1, + "amount": 500000.00, + "status": "pending", + "created_at": "2024-05-03T10:00:00.000000Z", + "wallet": { + "user": { + "id": 1, + "name": "John Doe", + "email": "john@example.com" + } + }, + "bank_account": { + "bank_name": "BCA", + "account_number": "1234567890", + "account_holder_name": "John Doe" + } + } + ], + "message": "Pending withdrawals retrieved successfully" +} +``` + +### Get Pending Bank Accounts +```http +GET /api/admin/bank-accounts/pending +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Response:** +```json +{ + "success": true, + "data": [ + { + "id": 1, + "user_id": 2, + "bank_name": "BCA", + "account_number": "1234567890", + "account_holder_name": "John Doe", + "status": "pending", + "created_at": "2024-05-03T10:00:00.000000Z", + "updated_at": "2024-05-03T10:00:00.000000Z", + "user": { + "id": 2, + "name": "John Doe", + "email": "john@example.com", + "role": "penjahit" + } + } + ], + "message": "Pending bank accounts retrieved successfully" +} +``` + +### Process Withdrawal +```http +POST /api/admin/withdrawals/{withdrawal}/process +``` + +**Headers:** +``` +Authorization: Bearer {token} +Content-Type: multipart/form-data +``` + +**Request Body:** +```json +{ + "status": "processing", + "proof_of_payment": [file] +} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "id": 1, + "amount": 500000.00, + "status": "processing", + "proof_of_payment": "proof_of_payments/abc123.jpg", + "updated_at": "2024-05-03T11:00:00.000000Z" + }, + "message": "Withdrawal status updated successfully" +} +``` + +### Complete Withdrawal +```http +POST /api/admin/withdrawals/{withdrawal}/complete +``` + +**Headers:** +``` +Authorization: Bearer {token} +``` + +**Response:** +```json +{ + "success": true, + "data": { + "id": 1, + "amount": 500000.00, + "status": "completed", + "processed_at": "2024-05-03T12:00:00.000000Z", + "updated_at": "2024-05-03T12:00:00.000000Z" + }, + "message": "Withdrawal completed successfully" +} +``` + +## Error Responses + +### Validation Error +```json +{ + "success": false, + "data": { + "bank_name": ["The bank name field is required."], + "account_number": ["The account number field is required."] + }, + "message": "Validation Error." +} +``` + +### Insufficient Balance +```json +{ + "success": false, + "data": { + "error": "Insufficient balance." + }, + "message": "Error." +} +``` + +### Invalid Bank Account +```json +{ + "success": false, + "data": { + "error": "Invalid bank account." + }, + "message": "Error." +} +``` + +## Status Codes + +- 200: Success +- 201: Created +- 400: Bad Request +- 401: Unauthorized +- 403: Forbidden +- 404: Not Found +- 422: Validation Error +- 500: Server Error \ No newline at end of file diff --git a/TA_API/documentation.md b/TA_API/documentation.md new file mode 100644 index 0000000..ac03bc3 --- /dev/null +++ b/TA_API/documentation.md @@ -0,0 +1,1081 @@ +# Project Jahit API Documentation + +## Deskripsi Proyek + +Project Jahit adalah platform yang menghubungkan pelanggan dengan penjahit. API ini menyediakan endpoint untuk mengelola registrasi pengguna, pencarian penjahit, pemesanan jasa, manajemen galeri dan layanan penjahit, serta sistem rating. + +## Base URL + +``` +http://localhost:8000/api +``` + +## Autentikasi + +API ini menggunakan Laravel Sanctum untuk autentikasi. Token akan diberikan setelah login dan harus disertakan dalam header setiap permintaan ke endpoint yang terproteksi. + +Format header: + +``` +Authorization: Bearer {token} +``` + +## Roles dan Hak Akses + +Sistem memiliki 3 role pengguna: + +- **admin** - Administrator platform +- **penjahit** - Penjahit/Penyedia jasa +- **pelanggan** - Pelanggan/Pengguna jasa + +## Endpoint API + +### Endpoint Publik + +#### Test API + +``` +GET /test +``` + +Response: + +```json +{ + "message": "API is working" +} +``` + +#### Spesialisasi + +``` +GET /specializations +``` + +Mendapatkan semua spesialisasi penjahit yang tersedia. + +``` +GET /specializations/all +``` + +Mendapatkan semua spesialisasi dengan detail lengkap. + +#### Pencarian Penjahit + +``` +GET /tailors/search?specialization={id} +``` + +Mencari penjahit berdasarkan spesialisasi. + +#### Detail Penjahit + +``` +GET /tailors/{id} +``` + +Mendapatkan detail informasi penjahit berdasarkan ID. + +``` +GET /tailors/{tailor}/services +``` + +Mendapatkan daftar layanan yang disediakan penjahit. + +``` +GET /tailors/{tailor}/gallery +``` + +Mendapatkan galeri foto penjahit. + +``` +GET /tailors/{tailor}/ratings +``` + +Mendapatkan ulasan dan rating untuk penjahit. + +### Autentikasi + +#### Pelanggan + +``` +POST /pelanggan/register +``` + +Registrasi akun pelanggan baru. + +Body: + +```json +{ + "name": "Nama Pelanggan", + "email": "pelanggan@example.com", + "password": "password", + "password_confirmation": "password", + "phone_number": "08123456789", + "address": "Alamat Lengkap" +} +``` + +``` +POST /pelanggan/login +``` + +Login sebagai pelanggan. + +Body: + +```json +{ + "email": "pelanggan@example.com", + "password": "password" +} +``` + +Response: + +```json +{ + "user": { + "id": 1, + "name": "Nama Pelanggan", + "email": "pelanggan@example.com", + "role": "pelanggan", + ... + }, + "token": "access_token_string" +} +``` + +#### Penjahit + +``` +POST /penjahit/register +``` + +Registrasi akun penjahit baru. + +Body: + +```json +{ + "name": "Nama Penjahit", + "email": "penjahit@example.com", + "password": "password", + "password_confirmation": "password", + "phone_number": "08123456789", + "address": "Alamat Lengkap", + "shop_description": "Deskripsi toko jahit", + "latitude": -6.123456, + "longitude": 106.123456, + "specializations": [1, 2] +} +``` + +``` +POST /penjahit/login +``` + +Login sebagai penjahit. + +Body: + +```json +{ + "email": "penjahit@example.com", + "password": "password" +} +``` + +#### Admin + +``` +POST /admin/login +``` + +Login sebagai admin. + +Body: + +```json +{ + "email": "admin@example.com", + "password": "password" +} +``` + +#### Lupa Password + +``` +POST /pelanggan/forgot-password +POST /penjahit/forgot-password +``` + +Mengirimkan email reset password. + +Body: + +```json +{ + "email": "user@example.com" +} +``` + +``` +POST /pelanggan/reset-password +POST /penjahit/reset-password +``` + +Reset password dengan token. + +Body: + +```json +{ + "email": "user@example.com", + "password": "new_password", + "password_confirmation": "new_password", + "token": "reset_token" +} +``` + +#### Logout + +``` +POST /logout +``` + +Logout pengguna (invalidasi token). + +Header: + +``` +Authorization: Bearer {token} +``` + +### Endpoint Profil + +``` +GET /profile +``` + +Mendapatkan informasi profil pengguna yang terautentikasi. + +``` +POST /profile +``` + +Mengupdate informasi profil pengguna. + +Body: + +```json +{ + "name": "Nama Baru", + "phone_number": "08123456789", + "address": "Alamat Baru" +} +``` + +``` +POST /profile/photo +``` + +Mengupload foto profil. + +Body (multipart/form-data): + +``` +profile_photo: [file] +``` + +### Endpoint Pelanggan + +#### Dashboard + +``` +GET /dashboard +``` + +Mendapatkan data dashboard pelanggan. + +#### Booking + +``` +GET /bookings/customer +``` + +Mendapatkan semua booking yang dilakukan pelanggan. + +``` +GET /bookings/customer/status/{status} +``` + +Mendapatkan booking pelanggan berdasarkan status (reservasi, diproses, selesai, dibatalkan). + +``` +GET /bookings/{booking} +``` + +Mendapatkan detail booking. + +``` +POST /tailors/{tailor}/book +``` + +Membuat booking baru ke penjahit. + +Body: + +```json +{ + "appointment_date": "2023-05-01", + "appointment_time": "10:00", + "service_type": "Jahit Baju", + "category": "Baju Wanita", + "notes": "Catatan tambahan", + "total_price": 150000 +} +``` + +``` +POST /bookings +``` + +Membuat booking baru. + +Body (multipart/form-data): + +``` +customer_id: 1 +tailor_id: 2 +appointment_date: 2023-05-01 +appointment_time: 10:00 +service_type: Jahit Baju +category: Baju Wanita +notes: Catatan tambahan +design_photo: [file] +total_price: 150000 +``` + +``` +POST /bookings/{booking}/cancel +``` + +Membatalkan booking. + +``` +POST /bookings/{booking}/rate +``` + +Memberikan rating dan ulasan. + +Body: + +```json +{ + "rating": 5, + "review": "Pelayanan sangat baik" +} +``` + +``` +PUT /ratings/{rating} +``` + +Mengupdate rating dan ulasan. + +Body: + +```json +{ + "rating": 4, + "review": "Pelayanan baik" +} +``` + +``` +POST /bookings/{booking}/completion-payment +``` + +Menyelesaikan pembayaran akhir booking. + +### Endpoint Penjahit + +#### Dashboard + +``` +GET /penjahit/dashboard +``` + +Mendapatkan data dashboard penjahit. + +#### Pembayaran + +``` +POST /bookings/{booking}/payment +``` + +Mengubah status pembayaran booking menjadi paid (hanya penjahit yang dapat melakukan). + +Body: + +```json +{ + "payment_status": "paid" +} +``` + +``` +POST /bookings/{booking}/completion-payment +``` + +Menyelesaikan pembayaran akhir booking dan mengatur tanggal pengambilan (hanya penjahit yang dapat melakukan). + +Body: + +```json +{ + "pickup_date": "2023-05-15" +} +``` + +#### Spesialisasi + +``` +POST /penjahit/specializations +``` + +Mengupdate spesialisasi penjahit. + +Body: + +```json +{ + "specializations": [1, 3, 5] +} +``` + +#### Kalender + +``` +GET /penjahit/calendar/{month}/{year} +``` + +Mendapatkan jadwal booking dalam bulan dan tahun tertentu. + +``` +GET /penjahit/calendar/date/{date} +``` + +Mendapatkan jadwal booking pada tanggal tertentu. + +#### Profil Toko + +``` +GET /penjahit/shop-profile +``` + +Mendapatkan profil toko penjahit. + +``` +POST /penjahit/shop-profile +``` + +Mengupdate profil toko penjahit. + +Body: + +```json +{ + "shop_description": "Deskripsi toko baru", + "address": "Alamat toko baru", + "latitude": -6.123456, + "longitude": 106.123456 +} +``` + +``` +DELETE /penjahit/shop-profile/photo +``` + +Menghapus foto profil toko. + +#### Galeri + +``` +GET /penjahit/gallery +``` + +Mendapatkan semua galeri penjahit. + +``` +POST /penjahit/gallery +``` + +Menambahkan foto ke galeri penjahit. + +Body (multipart/form-data): + +``` +photo: [file] +description: Deskripsi foto +``` + +``` +PUT /penjahit/gallery/{gallery} +``` + +Mengupdate deskripsi foto galeri. + +Body: + +```json +{ + "description": "Deskripsi baru" +} +``` + +``` +DELETE /penjahit/gallery/{gallery} +``` + +Menghapus foto dari galeri. + +#### Layanan + +``` +GET /penjahit/services +``` + +Mendapatkan semua layanan penjahit. + +``` +POST /penjahit/services +``` + +Menambahkan layanan baru. + +Body: + +```json +{ + "name": "Nama Layanan", + "description": "Deskripsi layanan", + "price": 100000, + "is_available": true +} +``` + +``` +PUT /penjahit/services/{service} +``` + +Mengupdate informasi layanan. + +Body: + +```json +{ + "name": "Nama Layanan Baru", + "description": "Deskripsi baru", + "price": 150000, + "is_available": true +} +``` + +``` +DELETE /penjahit/services/{service} +``` + +Menghapus layanan. + +``` +PATCH /penjahit/services/{service}/toggle +``` + +Mengaktifkan/menonaktifkan layanan. + +#### Booking + +``` +GET /penjahit/bookings +``` + +Mendapatkan semua booking penjahit. + +``` +GET /penjahit/bookings/status/{status} +``` + +Mendapatkan booking penjahit berdasarkan status. + +``` +POST /bookings/{booking}/accept +``` + +Menerima booking baru. + +``` +POST /bookings/{booking}/reject +``` + +Menolak booking. + +Body: + +```json +{ + "rejection_reason": "Jadwal penuh" +} +``` + +``` +PATCH /bookings/{booking}/status +``` + +Mengupdate status booking. + +Body: + +```json +{ + "status": "diproses" +} +``` + +``` +PATCH /bookings/{booking}/price +``` + +Mengupdate harga booking. + +Body: + +```json +{ + "total_price": 200000 +} +``` + +``` +POST /bookings/{booking}/measurements +``` + +Mengupdate ukuran jahitan. + +Body: + +```json +{ + "measurements": { + "lingkar_dada": 90, + "lingkar_pinggang": 70, + "panjang_lengan": 60 + } +} +``` + +``` +POST /bookings/{booking}/repair +``` + +Mengupdate detail perbaikan. + +Body (multipart/form-data): + +``` +repair_details: {"jenis_perbaikan": "Ubah ukuran", "bagian": "Lengan"} +repair_notes: Catatan perbaikan +repair_photo: [file] +``` + +``` +POST /bookings/{booking}/complete +``` + +Menyelesaikan booking. + +Body (multipart/form-data): + +``` +completion_notes: Catatan penyelesaian +completion_photo: [file] +pickup_date: 2023-05-15 +``` + +### Endpoint Admin + +#### Dashboard + +``` +GET /admin/dashboard +``` + +Mendapatkan data dashboard admin. + +#### Manajemen Pelanggan + +``` +GET /customers +``` + +Mendapatkan semua data pelanggan. + +``` +GET /customers/{id} +``` + +Mendapatkan detail pelanggan. + +#### Manajemen Booking + +``` +GET /bookings +``` + +Mendapatkan semua data booking. + +#### Manajemen Penjahit + +``` +GET /tailors +``` + +Mendapatkan semua data penjahit. + +``` +GET /tailors/all +``` + +Mendapatkan semua data penjahit tanpa filter rating. + +## Model Data + +### User + +- id +- name +- email +- password +- role (admin, penjahit, pelanggan) +- phone_number +- address +- shop_description (untuk penjahit) +- profile_photo +- latitude +- longitude +- created_at +- updated_at + +### Booking + +- id +- customer_id +- tailor_id +- appointment_date +- appointment_time +- service_type +- category +- design_photo +- notes +- status (reservasi, diproses, selesai, dibatalkan) +- total_price +- payment_status (unpaid, paid) +- measurements +- repair_details +- repair_photo +- repair_notes +- completion_photo +- completion_notes +- accepted_at +- rejected_at +- completed_at +- rejection_reason +- pickup_date +- created_at +- updated_at + +### TailorSpecialization + +- id +- name +- description +- photo +- created_at +- updated_at + +### TailorService + +- id +- user_id +- name +- description +- price +- is_available +- created_at +- updated_at + +### TailorGallery + +- id +- user_id +- photo +- description +- created_at +- updated_at + +### TailorRating + +- id +- booking_id +- tailor_id +- customer_id +- rating +- review +- created_at +- updated_at + +## Kode Status HTTP + +- 200 OK - Request berhasil +- 201 Created - Resource berhasil dibuat +- 400 Bad Request - Request tidak valid +- 401 Unauthorized - Tidak terotentikasi +- 403 Forbidden - Tidak memiliki izin +- 404 Not Found - Resource tidak ditemukan +- 422 Unprocessable Entity - Validasi gagal +- 500 Internal Server Error - Kesalahan server + +## Format Error Response + +```json +{ + "message": "Pesan error", + "errors": { + "field1": ["Error message 1", "Error message 2"], + "field2": ["Error message"] + } +} +``` + +## Contoh Penggunaan + +### Registrasi Pelanggan + +Request: + +``` +POST /api/pelanggan/register +Content-Type: application/json + +{ + "name": "John Doe", + "email": "john@example.com", + "password": "password123", + "password_confirmation": "password123", + "phone_number": "08123456789", + "address": "Jl. Example No. 123" +} +``` + +Response: + +``` +200 OK +Content-Type: application/json + +{ + "user": { + "id": 1, + "name": "John Doe", + "email": "john@example.com", + "role": "pelanggan", + "phone_number": "08123456789", + "address": "Jl. Example No. 123", + "created_at": "2023-05-01T10:00:00.000000Z", + "updated_at": "2023-05-01T10:00:00.000000Z" + }, + "token": "access_token_string" +} +``` + +### Penjahit Mengubah Status Pembayaran + +Request: + +``` +POST /api/bookings/1/payment +Content-Type: application/json +Authorization: Bearer {token_penjahit} + +{ + "payment_status": "paid" +} +``` + +Response: + +``` +200 OK +Content-Type: application/json + +{ + "status": "success", + "message": "Status pembayaran berhasil diubah menjadi paid oleh penjahit.", + "data": { + "booking": { + "id": 1, + "customer_name": "John Doe", + "payment_status": "paid", + "status": "reservasi", + "total_price": "150000.00", + "appointment_date": "2023-05-10" + } + } +} +``` + +### Penjahit Menyelesaikan Pembayaran Akhir + +Request: + +``` +POST /api/bookings/1/completion-payment +Content-Type: application/json +Authorization: Bearer {token_penjahit} + +{ + "pickup_date": "2023-05-15" +} +``` + +Response: + +``` +200 OK +Content-Type: application/json + +{ + "status": "success", + "message": "Pembayaran telah dikonfirmasi dan tanggal pengambilan berhasil diatur", + "data": { + "booking": { + "id": 1, + "customer_name": "John Doe", + "customer_phone": "08123456789", + "payment_status": "paid", + "status": "selesai", + "pickup_date": "2023-05-15" + }, + "message": "Pembayaran telah dikonfirmasi oleh penjahit", + "pickup_info": { + "date": "2023-05-15", + "status": "Sudah dibayar" + } + } +} +``` + +### Pencarian Penjahit + +Request: + +``` +GET /api/tailors/search?specialization=1 +Authorization: Bearer {token} +``` + +Response: + +``` +200 OK +Content-Type: application/json + +{ + "tailors": [ + { + "id": 2, + "name": "Tailor Shop", + "address": "Jl. Tailor No. 456", + "shop_description": "Toko jahit profesional", + "profile_photo": "storage/profile_photos/photo.jpg", + "rating": 4.5, + "specializations": [ + { + "id": 1, + "name": "Jahit Baju Wanita" + } + ] + } + ] +} +``` + +### Membuat Booking + +Request: + +``` +POST /api/bookings +Content-Type: multipart/form-data +Authorization: Bearer {token} + +customer_id: 1 +tailor_id: 2 +appointment_date: 2023-05-10 +appointment_time: 14:00 +service_type: Jahit Baju +category: Kemeja +notes: Bahan sudah tersedia +design_photo: [file upload] +total_price: 150000 +``` + +Response: + +``` +201 Created +Content-Type: application/json + +{ + "booking": { + "id": 1, + "customer_id": 1, + "tailor_id": 2, + "appointment_date": "2023-05-10", + "appointment_time": "14:00", + "service_type": "Jahit Baju", + "category": "Kemeja", + "notes": "Bahan sudah tersedia", + "design_photo": "storage/design_photos/design.jpg", + "status": "reservasi", + "total_price": "150000.00", + "payment_status": "unpaid", + "created_at": "2023-05-01T10:30:00.000000Z", + "updated_at": "2023-05-01T10:30:00.000000Z" + } +} +``` + +## File dan Media + +### Upload File + +Untuk endpoint yang memerlukan upload file, gunakan format `multipart/form-data` dan kirimkan file sebagai form field. + +### Akses File Media + +File media bisa diakses dengan URL: + +``` +http://localhost:8000/storage/{path} +``` + +Contoh: + +``` +http://localhost:8000/storage/design_photos/file.jpg +http://localhost:8000/storage/gallery_photos/photo.jpg +http://localhost:8000/storage/profile_photos/avatar.jpg +``` diff --git a/TA_API/package.json b/TA_API/package.json new file mode 100644 index 0000000..739172b --- /dev/null +++ b/TA_API/package.json @@ -0,0 +1,16 @@ +{ + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.0.0", + "axios": "^1.8.2", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "tailwindcss": "^4.0.0", + "vite": "^6.0.11" + } +} diff --git a/TA_API/phpunit.xml b/TA_API/phpunit.xml new file mode 100644 index 0000000..506b9a3 --- /dev/null +++ b/TA_API/phpunit.xml @@ -0,0 +1,33 @@ + + + + + tests/Unit + + + tests/Feature + + + + + app + + + + + + + + + + + + + + + + diff --git a/TA_API/postman_collection.json b/TA_API/postman_collection.json new file mode 100644 index 0000000..5136b65 --- /dev/null +++ b/TA_API/postman_collection.json @@ -0,0 +1,298 @@ +{ + "info": { + "name": "Project Jahit API - Email & Password", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "API untuk verifikasi email dan reset password pada Project Jahit" + }, + "item": [ + { + "name": "1. Autentikasi", + "item": [ + { + "name": "Login Pelanggan", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/pelanggan/login", + "host": ["{{base_url}}"], + "path": ["pelanggan", "login"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\"\n}" + }, + "description": "Login sebagai pelanggan untuk mendapatkan token autentikasi" + }, + "response": [] + }, + { + "name": "Login Penjahit", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/penjahit/login", + "host": ["{{base_url}}"], + "path": ["penjahit", "login"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\"\n}" + }, + "description": "Login sebagai penjahit untuk mendapatkan token autentikasi" + }, + "response": [] + } + ], + "description": "Endpoint untuk autentikasi pengguna" + }, + { + "name": "2. Verifikasi Email", + "item": [ + { + "name": "Kirim Email Verifikasi", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/email/verification-notification", + "host": ["{{base_url}}"], + "path": ["email", "verification-notification"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{token}}" + } + ], + "description": "Mengirim email verifikasi ke alamat email pengguna" + }, + "response": [] + }, + { + "name": "Kirim Ulang Email Verifikasi", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/email/verification-resend", + "host": ["{{base_url}}"], + "path": ["email", "verification-resend"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Authorization", + "value": "Bearer {{token}}" + } + ], + "description": "Mengirim ulang email verifikasi ke alamat email pengguna" + }, + "response": [] + }, + { + "name": "Verifikasi Email (Manual)", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/email/verify/{{user_id}}/{{hash}}?expires={{expires}}&signature={{signature}}", + "host": ["{{base_url}}"], + "path": ["email", "verify", "{{user_id}}", "{{hash}}"], + "query": [ + { + "key": "expires", + "value": "{{expires}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + } + ], + "description": "Verifikasi email dengan link yang dikirim ke email (biasanya diakses langsung dari email)" + }, + "response": [] + } + ], + "description": "Endpoint untuk verifikasi alamat email pengguna" + }, + { + "name": "3. Reset Password", + "item": [ + { + "name": "Request Reset Password Pelanggan", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/pelanggan/forgot-password", + "host": ["{{base_url}}"], + "path": ["pelanggan", "forgot-password"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\"\n}" + }, + "description": "Meminta PIN reset password untuk pelanggan" + }, + "response": [] + }, + { + "name": "Request Reset Password Penjahit", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/penjahit/forgot-password", + "host": ["{{base_url}}"], + "path": ["penjahit", "forgot-password"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\"\n}" + }, + "description": "Meminta PIN reset password untuk penjahit" + }, + "response": [] + }, + { + "name": "Reset Password Pelanggan", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/pelanggan/reset-password", + "host": ["{{base_url}}"], + "path": ["pelanggan", "reset-password"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{new_password}}\",\n \"password_confirmation\": \"{{new_password}}\",\n \"pin\": \"{{reset_pin}}\"\n}" + }, + "description": "Reset password pelanggan dengan PIN yang diterima via email" + }, + "response": [] + }, + { + "name": "Reset Password Penjahit", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/penjahit/reset-password", + "host": ["{{base_url}}"], + "path": ["penjahit", "reset-password"] + }, + "header": [ + { + "key": "Accept", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{new_password}}\",\n \"password_confirmation\": \"{{new_password}}\",\n \"pin\": \"{{reset_pin}}\"\n}" + }, + "description": "Reset password penjahit dengan PIN yang diterima via email" + }, + "response": [] + } + ], + "description": "Endpoint untuk reset password pengguna" + } + ], + "variable": [ + { + "key": "base_url", + "value": "http://localhost:8000/api" + }, + { + "key": "email", + "value": "your.email@example.com" + }, + { + "key": "password", + "value": "your_password" + }, + { + "key": "token", + "value": "your_auth_token" + }, + { + "key": "new_password", + "value": "your_new_password" + }, + { + "key": "reset_pin", + "value": "123456" + } + ] +} \ No newline at end of file diff --git a/TA_API/project_jahit.sql b/TA_API/project_jahit.sql new file mode 100644 index 0000000..052c9be --- /dev/null +++ b/TA_API/project_jahit.sql @@ -0,0 +1,636 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost:3306 +-- Generation Time: Mar 26, 2025 at 07:09 AM +-- Server version: 8.0.30 +-- PHP Version: 8.2.27 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `project_jahit` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `bookings` +-- + +CREATE TABLE `bookings` ( + `id` bigint UNSIGNED NOT NULL, + `customer_id` bigint UNSIGNED NOT NULL, + `tailor_id` bigint UNSIGNED NOT NULL, + `appointment_date` date NOT NULL, + `appointment_time` time NOT NULL, + `service_type` enum('Perbaikan','Jahit Baru') COLLATE utf8mb4_unicode_ci NOT NULL, + `category` enum('Atasan','Bawahan','Terusan') COLLATE utf8mb4_unicode_ci NOT NULL, + `design_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `notes` text COLLATE utf8mb4_unicode_ci, + `status` enum('reservasi','diproses','selesai','dibatalkan') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'reservasi', + `total_price` decimal(10,2) DEFAULT NULL, + `payment_status` enum('unpaid','paid') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'unpaid', + `measurements` json DEFAULT NULL, + `repair_details` json DEFAULT NULL, + `repair_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `repair_notes` text COLLATE utf8mb4_unicode_ci, + `completion_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `completion_notes` text COLLATE utf8mb4_unicode_ci, + `accepted_at` timestamp NULL DEFAULT NULL, + `rejected_at` timestamp NULL DEFAULT NULL, + `completed_at` timestamp NULL DEFAULT NULL, + `rejection_reason` text COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `bookings` +-- + +INSERT INTO `bookings` (`id`, `customer_id`, `tailor_id`, `appointment_date`, `appointment_time`, `service_type`, `category`, `design_photo`, `notes`, `status`, `total_price`, `payment_status`, `measurements`, `repair_details`, `repair_photo`, `repair_notes`, `completion_photo`, `completion_notes`, `accepted_at`, `rejected_at`, `completed_at`, `rejection_reason`, `created_at`, `updated_at`) VALUES +(1, 5, 2, '2025-03-26', '09:00:00', 'Jahit Baru', 'Atasan', 'designs/design1.jpg', 'Mau warna merah maroon', 'reservasi', '500000.00', 'paid', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(2, 6, 3, '2025-03-27', '10:00:00', 'Jahit Baru', 'Bawahan', 'designs/design2.jpg', 'Mau warna hitam', 'diproses', '350000.00', 'paid', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(3, 7, 4, '2025-03-25', '11:00:00', 'Perbaikan', 'Atasan', 'designs/design3.jpg', 'Perbaikan jahitan yang lepas', 'selesai', '100000.00', 'paid', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(4, 13, 3, '2025-04-01', '14:00:00', 'Jahit Baru', 'Bawahan', NULL, 'Jahit celana panjang dengan bahan katun', 'reservasi', NULL, 'unpaid', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-25 00:59:47', '2025-03-25 00:59:47'), +(5, 13, 3, '2025-04-01', '14:00:00', 'Jahit Baru', 'Bawahan', NULL, 'Celana bahan katun warna hitam', 'reservasi', NULL, 'unpaid', '[{\"name\": \"lingkar_pinggang\", \"unit\": \"cm\", \"value\": 82}, {\"name\": \"lingkar_pinggul\", \"unit\": \"cm\", \"value\": 96}, {\"name\": \"panjang_celana\", \"unit\": \"cm\", \"value\": 98}, {\"name\": \"lingkar_paha\", \"unit\": \"cm\", \"value\": 58}, {\"name\": \"lingkar_lutut\", \"unit\": \"cm\", \"value\": 40}, {\"name\": \"lingkar_kaki\", \"unit\": \"cm\", \"value\": 32}]', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-25 01:10:03', '2025-03-25 01:10:03'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cache` +-- + +CREATE TABLE `cache` ( + `key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `value` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `expiration` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cache_locks` +-- + +CREATE TABLE `cache_locks` ( + `key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `owner` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `expiration` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `customer_specialization` +-- + +CREATE TABLE `customer_specialization` ( + `id` bigint UNSIGNED NOT NULL, + `user_id` bigint UNSIGNED NOT NULL, + `tailor_specialization_id` bigint UNSIGNED NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `customer_specialization` +-- + +INSERT INTO `customer_specialization` (`id`, `user_id`, `tailor_specialization_id`, `created_at`, `updated_at`) VALUES +(1, 13, 3, NULL, NULL), +(2, 13, 5, NULL, NULL), +(3, 13, 9, NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `failed_jobs` +-- + +CREATE TABLE `failed_jobs` ( + `id` bigint UNSIGNED NOT NULL, + `uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `connection` text COLLATE utf8mb4_unicode_ci NOT NULL, + `queue` text COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `jobs` +-- + +CREATE TABLE `jobs` ( + `id` bigint UNSIGNED NOT NULL, + `queue` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `attempts` tinyint UNSIGNED NOT NULL, + `reserved_at` int UNSIGNED DEFAULT NULL, + `available_at` int UNSIGNED NOT NULL, + `created_at` int UNSIGNED NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `job_batches` +-- + +CREATE TABLE `job_batches` ( + `id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `total_jobs` int NOT NULL, + `pending_jobs` int NOT NULL, + `failed_jobs` int NOT NULL, + `failed_job_ids` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `options` mediumtext COLLATE utf8mb4_unicode_ci, + `cancelled_at` int DEFAULT NULL, + `created_at` int NOT NULL, + `finished_at` int DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `migrations` +-- + +CREATE TABLE `migrations` ( + `id` int UNSIGNED NOT NULL, + `migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `batch` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `migrations` +-- + +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES +(1, '0001_01_01_000001_create_cache_table', 1), +(2, '0001_01_01_000002_create_jobs_table', 1), +(3, '2014_10_12_000000_create_users_table', 1), +(4, '2024_03_23_000000_create_tailor_services_table', 1), +(5, '2024_03_23_create_bookings_table', 1), +(6, '2024_03_23_create_tailor_ratings_table', 1), +(7, '2024_03_23_create_tailor_specializations_table', 1), +(8, '2025_03_23_110103_create_sessions_table', 1), +(9, '2025_03_23_112534_create_personal_access_tokens_table', 1), +(10, '2025_03_25_052708_add_measurements_to_bookings_table', 2), +(11, '2025_03_25_053140_add_measurements_to_bookings_table', 3), +(12, '2025_03_25_061103_create_customer_specialization_table', 4), +(13, '2025_03_25_061144_add_coordinates_to_users_table', 4); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `personal_access_tokens` +-- + +CREATE TABLE `personal_access_tokens` ( + `id` bigint UNSIGNED NOT NULL, + `tokenable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `tokenable_id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `token` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL, + `abilities` text COLLATE utf8mb4_unicode_ci, + `last_used_at` timestamp NULL DEFAULT NULL, + `expires_at` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `personal_access_tokens` +-- + +INSERT INTO `personal_access_tokens` (`id`, `tokenable_type`, `tokenable_id`, `name`, `token`, `abilities`, `last_used_at`, `expires_at`, `created_at`, `updated_at`) VALUES +(1, 'App\\Models\\User', 5, 'auth_token', 'dc8aad22726b2620400823a768aae1d50ff7083060329e0ae95face9c68efc84', '[\"pelanggan\"]', NULL, NULL, '2025-03-24 14:23:02', '2025-03-24 14:23:02'), +(2, 'App\\Models\\User', 5, 'auth_token', 'f4373cc940078dba95fe744bc48e156608c62347e6430e7572c0eafe3cd7218b', '[\"pelanggan\"]', NULL, NULL, '2025-03-24 19:45:13', '2025-03-24 19:45:13'), +(3, 'App\\Models\\User', 8, 'auth_token', '6148f1621c3cfbef6d73ec190e9ecdd55e927331cf7b02214913c26869eb9dac', '[\"penjahit\"]', NULL, NULL, '2025-03-24 19:53:50', '2025-03-24 19:53:50'), +(4, 'App\\Models\\User', 8, 'auth_token', '432479a848414daeaf459835ea2e5b0ea6e23af676f7a48da9986cb3b013953e', '[\"penjahit\"]', NULL, NULL, '2025-03-24 19:57:18', '2025-03-24 19:57:18'), +(5, 'App\\Models\\User', 8, 'auth_token', 'a67932230ec732266da178298ac58f2465d93af4fce42477ff5c455a52522a52', '[\"penjahit\"]', '2025-03-24 20:19:49', NULL, '2025-03-24 20:02:50', '2025-03-24 20:19:49'), +(6, 'App\\Models\\User', 8, 'auth_token', '47b5668ff061e75ed9e5cb9885540c5ef27d92e6647fc6c8436e73666cb61d7a', '[\"penjahit\"]', '2025-03-24 20:25:40', NULL, '2025-03-24 20:21:25', '2025-03-24 20:25:40'), +(7, 'App\\Models\\User', 9, 'auth_token', '353dba4ffaf35a2b490b73f4c91101b41cfd656c22c58e1376aba64058b90c2f', '[\"penjahit\"]', NULL, NULL, '2025-03-24 21:02:57', '2025-03-24 21:02:57'), +(8, 'App\\Models\\User', 10, 'auth_token', '529bebe81179ed1280f608629196a794cbe6a6a9435a72874ffe345673925421', '[\"penjahit\"]', NULL, NULL, '2025-03-24 21:06:15', '2025-03-24 21:06:15'), +(9, 'App\\Models\\User', 10, 'auth_token', '57f803b9d036fb98a88f4ebba3c0a5a9acdde3cb6ab48348f500134b3353d5fc', '[\"penjahit\"]', '2025-03-24 21:45:01', NULL, '2025-03-24 21:12:03', '2025-03-24 21:45:01'), +(10, 'App\\Models\\User', 11, 'auth_token', '36b5daf355b146dda015b338781bb4c63d2c711d015a7e8038f734e46c620466', '[\"pelanggan\"]', NULL, NULL, '2025-03-24 23:02:48', '2025-03-24 23:02:48'), +(11, 'App\\Models\\User', 12, 'auth_token', '1449c16372977682d4da88fae630722cd9b40ac1e4b66413f4c9a0128eb8036e', '[\"pelanggan\"]', NULL, NULL, '2025-03-24 23:04:03', '2025-03-24 23:04:03'), +(12, 'App\\Models\\User', 12, 'auth_token', '77e1ddbceb795cbab25fe00b183a480d718ca8ec322eaf2e0f21a8252876188f', '[\"pelanggan\"]', NULL, NULL, '2025-03-24 23:05:32', '2025-03-24 23:05:32'), +(13, 'App\\Models\\User', 13, 'auth_token', '5f24887fe53d6c89571358624a0910de37b31b904740f671bc1b2e41cc150320', '[\"pelanggan\"]', '2025-03-25 02:00:44', NULL, '2025-03-24 23:13:51', '2025-03-25 02:00:44'), +(14, 'App\\Models\\User', 3, 'auth_token', '887a2ca7eb2ac83f6a452a04409828004df91e3726b19af96b752f19ad5a51a4', '[\"penjahit\"]', '2025-03-25 02:03:24', NULL, '2025-03-25 02:02:58', '2025-03-25 02:03:24'), +(15, 'App\\Models\\User', 3, 'auth_token', '1709e35fa00b423124756f38b540528966086b8cf37e906b9236a37919d82f01', '[\"penjahit\"]', '2025-03-25 23:57:03', NULL, '2025-03-25 02:05:53', '2025-03-25 23:57:03'), +(16, 'App\\Models\\User', 3, 'auth_token', 'ff32386ce195ed1b4bbacffa0104083bef1f93a872bf5c5e4bbb44a203653ca3', '[\"penjahit\"]', '2025-03-26 00:01:10', NULL, '2025-03-25 23:57:29', '2025-03-26 00:01:10'), +(17, 'App\\Models\\User', 3, 'auth_token', 'ac6e372d033bd6d6ce9cbcd6ee4947953ba1ad67f64c7b45e3c8491f5c856b01', '[\"penjahit\"]', '2025-03-26 00:05:58', NULL, '2025-03-26 00:01:20', '2025-03-26 00:05:58'), +(18, 'App\\Models\\User', 3, 'auth_token', '17484a3d3270863433fc2e1c8a4f79038737428ffefe5230c4525928d1319511', '[\"penjahit\"]', NULL, NULL, '2025-03-26 00:03:38', '2025-03-26 00:03:38'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sessions` +-- + +CREATE TABLE `sessions` ( + `id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `user_id` bigint UNSIGNED DEFAULT NULL, + `ip_address` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `user_agent` text COLLATE utf8mb4_unicode_ci, + `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `last_activity` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `sessions` +-- + +INSERT INTO `sessions` (`id`, `user_id`, `ip_address`, `user_agent`, `payload`, `last_activity`) VALUES +('WmfZwtW5bfN0GeCmG5JzMvHAc61wJfUulDECoDAL', NULL, '127.0.0.1', 'PostmanRuntime/7.43.2', 'YTozOntzOjY6Il90b2tlbiI7czo0MDoiZ1QwNmpQZXJYV1VLTW9aZ3BNOEh3dFlGUzhvaWtWU1NwSWhUTkZzRSI7czo5OiJfcHJldmlvdXMiO2E6MTp7czozOiJ1cmwiO3M6MjE6Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMCI7fXM6NjoiX2ZsYXNoIjthOjI6e3M6Mzoib2xkIjthOjA6e31zOjM6Im5ldyI7YTowOnt9fX0=', 1742872305); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_ratings` +-- + +CREATE TABLE `tailor_ratings` ( + `id` bigint UNSIGNED NOT NULL, + `booking_id` bigint UNSIGNED NOT NULL, + `customer_id` bigint UNSIGNED NOT NULL, + `tailor_id` bigint UNSIGNED NOT NULL, + `rating` decimal(2,1) NOT NULL, + `review` text COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_ratings` +-- + +INSERT INTO `tailor_ratings` (`id`, `booking_id`, `customer_id`, `tailor_id`, `rating`, `review`, `created_at`, `updated_at`) VALUES +(1, 3, 7, 4, '4.5', 'Hasil jahitan sangat rapi dan sesuai ekspektasi', '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(2, 2, 6, 3, '4.0', 'Pelayanan bagus, hasil jahitan sesuai', '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(3, 1, 5, 2, '5.0', 'Sangat puas dengan hasil jahitan', '2025-03-24 14:15:15', '2025-03-24 14:15:15'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_services` +-- + +CREATE TABLE `tailor_services` ( + `id` bigint UNSIGNED NOT NULL, + `user_id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `description` text COLLATE utf8mb4_unicode_ci NOT NULL, + `price` decimal(10,2) NOT NULL, + `category` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `estimated_days` int NOT NULL DEFAULT '1', + `is_available` tinyint(1) NOT NULL DEFAULT '1', + `service_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_services` +-- + +INSERT INTO `tailor_services` (`id`, `user_id`, `name`, `description`, `price`, `category`, `estimated_days`, `is_available`, `service_photo`, `created_at`, `updated_at`) VALUES +(1, 2, 'Jahit Baju Pesta', 'Jahit baju pesta dengan kualitas terbaik', '500000.00', 'Jahit Baru', 7, 1, 'services/baju_pesta.jpg', '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(2, 3, 'Jahit Baju Muslim', 'Jahit baju muslim dengan desain modern', '350000.00', 'Jahit Baru', 5, 1, 'services/baju_muslim.jpg', '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(3, 4, 'Perbaikan Baju', 'Perbaikan baju rusak atau tidak pas', '100000.00', 'Perbaikan', 3, 1, 'services/perbaikan.jpg', '2025-03-24 14:15:15', '2025-03-24 14:15:15'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_specializations` +-- + +CREATE TABLE `tailor_specializations` ( + `id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `icon` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_specializations` +-- + +INSERT INTO `tailor_specializations` (`id`, `name`, `icon`, `created_at`, `updated_at`) VALUES +(1, 'Celana', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(2, 'Rok', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(3, 'Kemeja', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(4, 'Seragam', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(5, 'Jas Blazer', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(6, 'Kebaya', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(7, 'Gaun', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(8, 'Gamis', NULL, '2025-03-23 07:12:26', '2025-03-23 07:12:26'), +(9, 'Baju Pesta', 'dress', '2025-03-24 14:15:13', '2025-03-24 14:15:13'), +(10, 'Baju Muslim', 'hijab', '2025-03-24 14:15:13', '2025-03-24 14:15:13'), +(11, 'Baju Casual', 'tshirt', '2025-03-24 14:15:13', '2025-03-24 14:15:13'), +(12, 'Baju Batik', 'shirt', '2025-03-24 14:15:13', '2025-03-24 14:15:13'), +(13, 'Baju Anak', 'child', '2025-03-24 14:15:13', '2025-03-24 14:15:13'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_specialization_user` +-- + +CREATE TABLE `tailor_specialization_user` ( + `user_id` bigint UNSIGNED NOT NULL, + `tailor_specialization_id` bigint UNSIGNED NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_specialization_user` +-- + +INSERT INTO `tailor_specialization_user` (`user_id`, `tailor_specialization_id`) VALUES +(8, 1), +(9, 1), +(10, 1), +(8, 2), +(9, 2), +(10, 2), +(2, 7), +(3, 8), +(3, 9), +(4, 11); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +CREATE TABLE `users` ( + `id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `role` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `phone_number` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `address` text COLLATE utf8mb4_unicode_ci, + `latitude` decimal(10,7) DEFAULT NULL, + `longitude` decimal(10,7) DEFAULT NULL, + `shop_description` text COLLATE utf8mb4_unicode_ci, + `profile_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `email_verified_at` timestamp NULL DEFAULT NULL, + `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `users` +-- + +INSERT INTO `users` (`id`, `name`, `email`, `password`, `role`, `phone_number`, `address`, `latitude`, `longitude`, `shop_description`, `profile_photo`, `email_verified_at`, `remember_token`, `created_at`, `updated_at`) VALUES +(1, 'Admin', 'admin@example.com', '$2y$12$1xjXUN3sKlXGEGge4Tgz3uknp4lKoKE/6omrtKskVUk5Pjh79iVYq', 'admin', '081234567890', 'Jl. Admin No. 1', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:13', '2025-03-24 14:15:13'), +(2, 'Budi Santoso', 'budi@example.com', '$2y$12$yrfioUpS/pdazTGJIZu1j.OLoXeLH68cEch7lePoYXUUNv/nWPcv6', 'penjahit', '081234567891', 'Jl. Penjahit No. 1', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:14', '2025-03-24 14:15:14'), +(3, 'Siti Rahayu', 'siti@example.com', '$2y$12$Zb/eL4QPg.Vp9yDtrJgb4eo9Coi03lLoEAFG.Se2d6FoVi9ZfyrU6', 'penjahit', '081234567892', 'Jl. Penjahit No. 2', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:14', '2025-03-24 14:15:14'), +(4, 'Ahmad Hidayat', 'ahmad@example.com', '$2y$12$/FLgAmjxFq41y/Fmb9dT9uruuL.dTtLhSVxVNX/1yin4Jz6cQHsNG', 'penjahit', '081234567893', 'Jl. Penjahit No. 3', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:14', '2025-03-24 14:15:14'), +(5, 'Dewi Putri', 'dewi@example.com', '$2y$12$UgRRTBfZ9GfkpvfANSZEVOcQgIM00t20CjMtG6/FM3wD2/3eePnPi', 'pelanggan', '081234567894', 'Jl. Pelanggan No. 1', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(6, 'Rudi Hermawan', 'rudi@example.com', '$2y$12$guYUbd7s2shTsM5az8K7Le2sN92m4zoWY4VCTtOA38qHG6maQ2LXi', 'pelanggan', '081234567895', 'Jl. Pelanggan No. 2', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(7, 'Linda Wijaya', 'linda@example.com', '$2y$12$jiuezuHqqBkTxf3F15YC5OM/ZOSoo5CPij7IGzbtJExxQi22AZU9i', 'pelanggan', '081234567896', 'Jl. Pelanggan No. 3', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 14:15:15', '2025-03-24 14:15:15'), +(8, 'Nama Toko Jahit', 'tk_jahit@gmail.com', '$2y$12$aGordReKcgkMGdWvBowHouCKlUEAuw.7PELi8e7KDj.vyhgHPQh76', 'penjahit', '081234567890', 'Alamat lengkap toko', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 19:53:50', '2025-03-24 19:53:50'), +(9, 'Toko Jahit Makmur', 'jahit.makmur@example.com', '$2y$12$69Ppk63oK/J.zE7rbOUKL.AAtn9zbOwRyUdNxru4aKIvttqWLE.IK', 'penjahit', '081234567891', 'Jl. Menjahit Indah No. 123, Jakarta Selatan', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 21:02:56', '2025-03-24 21:02:56'), +(10, 'Toko Jahit Suka', 'jahit.makmurr@example.com', '$2y$12$y7IySkko4ONipGqyz844L.ozq7u6xp546P5xVz0Js7bfTzlzLBdsO', 'penjahit', '081234567891', 'Jl. Menjahit Indah No. 123, Jakarta Selatan', NULL, NULL, 'Toko jahit terpercaya dengan pengalaman lebih dari 10 tahun. Menyediakan berbagai jasa jahit dan perbaikan pakaian dengan kualitas premium.', NULL, NULL, NULL, '2025-03-24 21:06:15', '2025-03-24 21:06:15'), +(11, 'Nama Pelanggan', 'pelanggan@example.com', '$2y$12$Dk4oUbw7/NRE1qvm87ykC.0ZxQHQXSSR.rgooSc31dif5VSV4ocg2', 'pelanggan', '081234567890', 'Alamat lengkap pelanggan', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 23:02:48', '2025-03-24 23:02:48'), +(12, 'Nama Pelanggan', 'pelanggan2@gmail.com', '$2y$12$n9TeZXeYUZBNhwsHWOC.AueCRdzr06syVdcmjUnYsMSyhYeDI5esu', 'pelanggan', '081234567890', 'Alamat lengkap pelanggan', NULL, NULL, NULL, NULL, NULL, NULL, '2025-03-24 23:04:03', '2025-03-24 23:04:03'), +(13, 'Pelanggan Baru', 'pelanggan.baru22@example.com', '$2y$12$vlH/SPHprFEYPxas23TBsOlJ0Ab53gr66Cs.eT45A69c7Dc2K2ISe', 'pelanggan', '081234567890', 'Jl. Pelanggan No. 123, Jakarta', '-6.1754000', '106.8272000', NULL, NULL, NULL, NULL, '2025-03-24 23:13:51', '2025-03-24 23:13:51'); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `bookings` +-- +ALTER TABLE `bookings` + ADD PRIMARY KEY (`id`), + ADD KEY `bookings_customer_id_foreign` (`customer_id`), + ADD KEY `bookings_tailor_id_foreign` (`tailor_id`); + +-- +-- Indexes for table `cache` +-- +ALTER TABLE `cache` + ADD PRIMARY KEY (`key`); + +-- +-- Indexes for table `cache_locks` +-- +ALTER TABLE `cache_locks` + ADD PRIMARY KEY (`key`); + +-- +-- Indexes for table `customer_specialization` +-- +ALTER TABLE `customer_specialization` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `customer_specialization_user_id_tailor_specialization_id_unique` (`user_id`,`tailor_specialization_id`), + ADD KEY `customer_specialization_tailor_specialization_id_foreign` (`tailor_specialization_id`); + +-- +-- Indexes for table `failed_jobs` +-- +ALTER TABLE `failed_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`); + +-- +-- Indexes for table `jobs` +-- +ALTER TABLE `jobs` + ADD PRIMARY KEY (`id`), + ADD KEY `jobs_queue_index` (`queue`); + +-- +-- Indexes for table `job_batches` +-- +ALTER TABLE `job_batches` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `migrations` +-- +ALTER TABLE `migrations` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `personal_access_tokens` +-- +ALTER TABLE `personal_access_tokens` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `personal_access_tokens_token_unique` (`token`), + ADD KEY `personal_access_tokens_tokenable_type_tokenable_id_index` (`tokenable_type`,`tokenable_id`); + +-- +-- Indexes for table `sessions` +-- +ALTER TABLE `sessions` + ADD PRIMARY KEY (`id`), + ADD KEY `sessions_user_id_index` (`user_id`), + ADD KEY `sessions_last_activity_index` (`last_activity`); + +-- +-- Indexes for table `tailor_ratings` +-- +ALTER TABLE `tailor_ratings` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `tailor_ratings_booking_id_customer_id_unique` (`booking_id`,`customer_id`), + ADD KEY `tailor_ratings_customer_id_foreign` (`customer_id`), + ADD KEY `tailor_ratings_tailor_id_foreign` (`tailor_id`); + +-- +-- Indexes for table `tailor_services` +-- +ALTER TABLE `tailor_services` + ADD PRIMARY KEY (`id`), + ADD KEY `tailor_services_user_id_foreign` (`user_id`); + +-- +-- Indexes for table `tailor_specializations` +-- +ALTER TABLE `tailor_specializations` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `tailor_specialization_user` +-- +ALTER TABLE `tailor_specialization_user` + ADD PRIMARY KEY (`user_id`,`tailor_specialization_id`), + ADD KEY `tailor_specialization_user_tailor_specialization_id_foreign` (`tailor_specialization_id`); + +-- +-- Indexes for table `users` +-- +ALTER TABLE `users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `users_email_unique` (`email`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `bookings` +-- +ALTER TABLE `bookings` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6; + +-- +-- AUTO_INCREMENT for table `customer_specialization` +-- +ALTER TABLE `customer_specialization` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- AUTO_INCREMENT for table `failed_jobs` +-- +ALTER TABLE `failed_jobs` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `jobs` +-- +ALTER TABLE `jobs` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `migrations` +-- +ALTER TABLE `migrations` + MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14; + +-- +-- AUTO_INCREMENT for table `personal_access_tokens` +-- +ALTER TABLE `personal_access_tokens` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=19; + +-- +-- AUTO_INCREMENT for table `tailor_ratings` +-- +ALTER TABLE `tailor_ratings` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- AUTO_INCREMENT for table `tailor_services` +-- +ALTER TABLE `tailor_services` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5; + +-- +-- AUTO_INCREMENT for table `tailor_specializations` +-- +ALTER TABLE `tailor_specializations` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14; + +-- +-- AUTO_INCREMENT for table `users` +-- +ALTER TABLE `users` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `bookings` +-- +ALTER TABLE `bookings` + ADD CONSTRAINT `bookings_customer_id_foreign` FOREIGN KEY (`customer_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `bookings_tailor_id_foreign` FOREIGN KEY (`tailor_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `customer_specialization` +-- +ALTER TABLE `customer_specialization` + ADD CONSTRAINT `customer_specialization_tailor_specialization_id_foreign` FOREIGN KEY (`tailor_specialization_id`) REFERENCES `tailor_specializations` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `customer_specialization_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `tailor_ratings` +-- +ALTER TABLE `tailor_ratings` + ADD CONSTRAINT `tailor_ratings_booking_id_foreign` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `tailor_ratings_customer_id_foreign` FOREIGN KEY (`customer_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `tailor_ratings_tailor_id_foreign` FOREIGN KEY (`tailor_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `tailor_services` +-- +ALTER TABLE `tailor_services` + ADD CONSTRAINT `tailor_services_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `tailor_specialization_user` +-- +ALTER TABLE `tailor_specialization_user` + ADD CONSTRAINT `tailor_specialization_user_tailor_specialization_id_foreign` FOREIGN KEY (`tailor_specialization_id`) REFERENCES `tailor_specializations` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `tailor_specialization_user_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/TA_API/public/.htaccess b/TA_API/public/.htaccess new file mode 100644 index 0000000..af4ef05 --- /dev/null +++ b/TA_API/public/.htaccess @@ -0,0 +1,47 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Mengizinkan akses ke file di storage + RewriteCond %{REQUEST_URI} ^/storage/(.*)$ + RewriteRule ^storage/(.*)$ storage/$1 [L,NC] + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Handle X-XSRF-Token Header + RewriteCond %{HTTP:x-xsrf-token} . + RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + + +# Tambahan untuk mengizinkan akses ke file + + Header set Access-Control-Allow-Origin "*" + Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" + Header set Access-Control-Allow-Headers "X-Requested-With, Content-Type, X-Token-Auth, Authorization" + + +# Mengizinkan akses ke file gambar dan dokumen + + + Require all granted + + + Order allow,deny + Allow from all + + diff --git a/TA_API/public/favicon.ico b/TA_API/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/TA_API/public/images/LogoGelap.png b/TA_API/public/images/LogoGelap.png new file mode 100644 index 0000000000000000000000000000000000000000..1cdc6cb219e15d5eb64ac4d759c9f3e62e94bdc0 GIT binary patch literal 5999 zcmcgwhdUeI*GH=@s_mDeR@K&$Xw_Cxn<7@th*2|QMQRJJqOBUOSsG%iU3*5*uU#v) z5H(XXtq~>0>-WBY!~47Ux%0WtIrq8e-g7^n^WF%o&CJNfNJB%ztgEA8LPJBFcF{k( zcIBd`Z0LwzGz>mER!ABeCf5HHTAB>>or_6Yq=~i~O~nw;`o-X~tEz!24NX-7(}@E; z4GqU-T@BUefwbH6AwD*%K|Oy+sA1ceHBOG=ZTAMMg$J~5sV(O-FcdI0A*y(FmhufA zClOQ(@Ve`@eHXc4TgV{ECBt8;Y2lev4kxQlJO5Kg#4CpT_V;cv>B-j9(8{(Esw+sX zhL{>z`&fY0Y)Wk+4wHV6HLvXIz1xP{Ya=U=#py2g^+KHU ztz+fyyXCfiwbq%wy8pB>dnFZ9Ls=5~Wd?@!*t`4|RpxEjPI{aGhc$U*9ggM-f(U#2 zsoaPCm)$*~%94mPJB@w(Juht1H+=EdhkWv5C^P^BXcyX}Oa3gfC{sV>TgM6&f8(2q zew~pqyT{+(CW+WtjB)ab)6b4#vask{A_}sA65DDyPCp`#Ss{1h>)Z`OLPE4&>1s7* z=Ubascv+AZGJvHr!z(p2DjZfRZ2F&1Bw#PWMCX(O5{?uE&MVdQORF;|Bi4!ANwy0K z+8CLr&Tp0(!SB!cn22vkdccCZJUSx#E?Z@nl*Z!>H3|PxkA|9#P7&i`|F_)X;c@h~ z=0X~#}8IAgQ({!Ii!-cX(OyYWn)fFa<3#Nt&!3@Vc*Db`0-w+zw%boXd|0WJ*w z>sLS3Dvup56{^>sCyb6h68ijbXh5MT@M{;#*~i8ak^hy?a#MM{MZjXQVq$vXMb|uE z!J!pK??b|h`{rDsmB$MJsOvOtQaZ>o;>SPsiT?n_tRaMEv{rg)Sx_Mqe4Y#sVpP{IhO_^Qxby zv#k{Gv$-+Ij?VD3MMq3zOU9PRo(vaLDR}?PR z*e}y2e*^S2SB5V6k(Q>`Xok7%>}?n&q<$Kdx{Yph9go_KURr?$w2J{phD7T%_!ulpsoDgY0*1>0bfS#}u!P^`?gN=VZr8E14GXu43Ly zdgMy=PIHA`IGB06mTEvpl?T1I;hTTF#FTwFVEzks>wy?+no z;NU^}bP0nc;P{ccgXd$X@UNadl5 zzj0jjk5EyB=kGRtW|qoXdrvbNAYx*&sH!)p*k6@oWjUU|9bi5YhH&Kz+z%=Z zdE∾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 NOji@EQK4oZ@jpOzQ9%Fz literal 0 HcmV?d00001 diff --git a/TA_API/public/images/logo.png b/TA_API/public/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f98b82c446b77130f177bfa14a4153b3d7724686 GIT binary patch literal 6166 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 KSby{G)Bgi@dbO$m literal 0 HcmV?d00001 diff --git a/TA_API/public/index.php b/TA_API/public/index.php new file mode 100644 index 0000000..ee8f07e --- /dev/null +++ b/TA_API/public/index.php @@ -0,0 +1,20 @@ +handleRequest(Request::capture()); diff --git a/TA_API/public/robots.txt b/TA_API/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/TA_API/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/TA_API/resources/css/app.css b/TA_API/resources/css/app.css new file mode 100644 index 0000000..3e6abea --- /dev/null +++ b/TA_API/resources/css/app.css @@ -0,0 +1,11 @@ +@import 'tailwindcss'; + +@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; +@source '../../storage/framework/views/*.php'; +@source '../**/*.blade.php'; +@source '../**/*.js'; + +@theme { + --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol', 'Noto Color Emoji'; +} diff --git a/TA_API/resources/js/app.js b/TA_API/resources/js/app.js new file mode 100644 index 0000000..e59d6a0 --- /dev/null +++ b/TA_API/resources/js/app.js @@ -0,0 +1 @@ +import './bootstrap'; diff --git a/TA_API/resources/js/bootstrap.js b/TA_API/resources/js/bootstrap.js new file mode 100644 index 0000000..5f1390b --- /dev/null +++ b/TA_API/resources/js/bootstrap.js @@ -0,0 +1,4 @@ +import axios from 'axios'; +window.axios = axios; + +window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; diff --git a/TA_API/resources/views/api-docs-original.blade.php b/TA_API/resources/views/api-docs-original.blade.php new file mode 100644 index 0000000..f5297aa --- /dev/null +++ b/TA_API/resources/views/api-docs-original.blade.php @@ -0,0 +1,1554 @@ + + + + + + + Dokumentasi API Project Jahit + + + + + + + +
+
+ + +
+
+

Pendahuluan

+

Project Jahit adalah platform yang menghubungkan pelanggan dengan penjahit. API ini menyediakan + endpoint untuk mengelola registrasi pengguna, pencarian penjahit, pemesanan jasa, manajemen + galeri dan layanan penjahit, serta sistem rating.

+ +

Base URL

+
http://localhost:8000/api
+
+ +
+

Autentikasi

+

API ini menggunakan Laravel Sanctum untuk autentikasi. Token akan diberikan setelah login dan + harus disertakan dalam header setiap permintaan ke endpoint yang terproteksi.

+ +

Format Header

+
Authorization: Bearer {token}
+
+ +
+

Role & Hak Akses

+

Sistem memiliki 3 role pengguna:

+
    +
  • admin - Administrator platform
  • +
  • penjahit - Penjahit/Penyedia jasa
  • +
  • pelanggan - Pelanggan/Pengguna jasa
  • +
+
+ +
+

Endpoint API

+ +
+

Endpoint Publik

+ +
+ GET + /test +

Tes koneksi API

+
Response
+
{
+  "message": "API is working"
+}
+
+ +
+ GET + /specializations +

Mendapatkan semua spesialisasi penjahit

+
+ +
+ GET + /tailors/search?specialization={id} +

Mencari penjahit berdasarkan spesialisasi

+
+ +
+ GET + /tailors/{id} +

Mendapatkan detail informasi penjahit

+
+
+ +
+

Autentikasi

+ +
+ POST + /pelanggan/register +

Registrasi akun pelanggan baru

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "name": "John Doe",
+    "email": "john@example.com",
+    "password": "password123",
+    "password_confirmation": "password123",
+    "phone_number": "08123456789",
+    "address": "Jl. Example No. 123"
+}
+
Validasi
+
    +
  • name - Wajib diisi, nama lengkap pengguna
  • +
  • email - Wajib diisi, format email, harus unik
  • +
  • password - Wajib diisi, minimal 8 karakter
  • +
  • password_confirmation - Wajib diisi, harus sama dengan password
  • +
  • phone_number - Wajib diisi, nomor telepon
  • +
  • address - Wajib diisi, alamat lengkap
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "role": "pelanggan",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Pendaftaran berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "email": ["Email sudah digunakan."],
+        "password": ["Password minimal harus 8 karakter."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /pelanggan/login +

Login sebagai pelanggan

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "email": "john@example.com",
+    "password": "password123"
+}
+
Validasi
+
    +
  • email - Wajib diisi, format email
  • +
  • password - Wajib diisi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "role": "pelanggan",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Login berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Email atau password tidak valid"
+    },
+    "message": "Authentication Error."
+}
+
+ +
+ POST + /penjahit/register +

Registrasi akun penjahit baru

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "name": "John Doe",
+    "email": "tailor@example.com",
+    "password": "password123",
+    "password_confirmation": "password123",
+    "phone_number": "08123456789",
+    "address": "Jl. Example No. 123",
+    "shop_description": "Jasa jahit profesional dengan pelayanan terbaik",
+    "specializations": [1, 2, 3]
+}
+
Validasi
+
    +
  • name - Wajib diisi, nama lengkap penjahit
  • +
  • email - Wajib diisi, format email, harus unik
  • +
  • password - Wajib diisi, minimal 8 karakter
  • +
  • password_confirmation - Wajib diisi, harus sama dengan password
  • +
  • phone_number - Wajib diisi, nomor telepon
  • +
  • address - Wajib diisi, alamat lengkap
  • +
  • shop_description - Wajib diisi, deskripsi toko/jasa
  • +
  • specializations - Wajib diisi, array ID spesialisasi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 2,
+            "name": "John Doe",
+            "email": "tailor@example.com",
+            "role": "penjahit",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "shop_description": "Jasa jahit profesional dengan pelayanan terbaik",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z",
+            "specializations": [
+                {
+                    "id": 1,
+                    "name": "Kemeja"
+                },
+                {
+                    "id": 2,
+                    "name": "Gaun"
+                },
+                {
+                    "id": 3,
+                    "name": "Celana"
+                }
+            ]
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Pendaftaran berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "email": ["Email sudah digunakan."],
+        "specializations": ["Spesialisasi wajib diisi."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /penjahit/login +

Login sebagai penjahit

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "email": "tailor@example.com",
+    "password": "password123"
+}
+
Validasi
+
    +
  • email - Wajib diisi, format email
  • +
  • password - Wajib diisi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 2,
+            "name": "John Doe",
+            "email": "tailor@example.com",
+            "role": "penjahit",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "shop_description": "Jasa jahit profesional dengan pelayanan terbaik",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Login berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Email atau password tidak valid"
+    },
+    "message": "Authentication Error."
+}
+
+ +
+ POST + /admin/login +

Login sebagai admin

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "email": "admin@example.com",
+    "password": "admin123"
+}
+
Validasi
+
    +
  • email - Wajib diisi, format email
  • +
  • password - Wajib diisi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 3,
+            "name": "Admin",
+            "email": "admin@example.com",
+            "role": "admin",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Login berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Email atau password tidak valid"
+    },
+    "message": "Authentication Error."
+}
+
+ +
+ POST + /logout +

Logout pengguna (invalidasi token)

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {},
+    "message": "Berhasil logout"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthenticated"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /email/verification-notification +

Mengirim ulang email verifikasi

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {},
+    "message": "Email verifikasi telah dikirim"
+}
+
+
+ +
+

Profil

+ +
+ GET + /profile +

Mendapatkan informasi profil pengguna

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "name": "John Doe",
+        "email": "john@example.com",
+        "role": "pelanggan",
+        "phone_number": "08123456789",
+        "address": "Jl. Example No. 123",
+        "profile_photo": "profile_photos/user1.jpg",
+        "created_at": "2023-05-01T10:00:00.000000Z",
+        "updated_at": "2023-05-01T10:00:00.000000Z"
+    },
+    "message": "Profil berhasil ditemukan"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthenticated"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /profile +

Mengupdate informasi profil pengguna

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "name": "John Doe Updated",
+    "phone_number": "087654321",
+    "address": "Jl. Updated No. 456",
+    "shop_description": "Deskripsi toko yang diupdate" // khusus penjahit
+}
+
Validasi
+
    +
  • name - Opsional, nama baru pengguna
  • +
  • phone_number - Opsional, nomor telepon baru
  • +
  • address - Opsional, alamat baru
  • +
  • shop_description - Opsional, deskripsi toko baru (hanya untuk penjahit)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "name": "John Doe Updated",
+        "email": "john@example.com",
+        "role": "pelanggan",
+        "phone_number": "087654321",
+        "address": "Jl. Updated No. 456",
+        "created_at": "2023-05-01T10:00:00.000000Z",
+        "updated_at": "2023-05-02T10:00:00.000000Z"
+    },
+    "message": "Profil berhasil diupdate"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "phone_number": ["Format nomor telepon tidak valid"]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /profile/photo +

Mengupload foto profil

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Request Body
+
{
+    "profile_photo": [file]
+}
+
Validasi
+
    +
  • profile_photo - Wajib diisi, file gambar, maksimal 2MB
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "name": "John Doe",
+        "profile_photo": "profile_photos/user1_updated.jpg"
+    },
+    "message": "Foto profil berhasil diupload"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "profile_photo": ["File harus berupa gambar dengan ukuran maksimal 2MB"]
+    },
+    "message": "Validation Error."
+}
+
+
+ +
+

Pelanggan

+ +
+ GET + /dashboard +

Mendapatkan data dashboard pelanggan

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "phone_number": "08123456789"
+        },
+        "bookings_count": {
+            "total": 5,
+            "ongoing": 2,
+            "completed": 3
+        },
+        "latest_bookings": [
+            {
+                "id": 3,
+                "transaction_code": "TRX-003",
+                "tailor_name": "Penjahit ABC",
+                "category": "Atasan",
+                "service_type": "Jahit Baru",
+                "status": "diproses",
+                "appointment_date": "2023-05-10"
+            }
+        ]
+    },
+    "message": "Dashboard data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /bookings/customer +

Mendapatkan semua booking yang dilakukan pelanggan

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • status (optional) - Filter berdasarkan status (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "transaction_code": "TRX-001",
+            "customer_id": 1,
+            "tailor_id": 2,
+            "appointment_date": "2023-05-05",
+            "appointment_time": "10:00",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "design_photo": "design_photos/design1.jpg",
+            "notes": "Mohon dibuat sesuai ukuran",
+            "status": "selesai",
+            "total_price": 150000,
+            "payment_status": "paid",
+            "payment_method": "Midtrans",
+            "completed_at": "2023-05-10T14:00:00.000000Z",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-10T14:00:00.000000Z",
+            "tailor": {
+                "id": 2,
+                "name": "Penjahit ABC",
+                "profile_photo": "profile_photos/tailor1.jpg",
+                "address": "Jl. Penjahit No. 123"
+            },
+            "rating": {
+                "id": 1,
+                "rating": 5,
+                "review": "Sangat puas dengan hasilnya"
+            }
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /bookings/customer/status/{status} +

Mendapatkan booking pelanggan berdasarkan status

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • status - Status booking (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "transaction_code": "TRX-001",
+            "tailor_name": "Penjahit ABC",
+            "tailor_photo": "profile_photos/tailor1.jpg",
+            "appointment_date": "2023-05-05",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "payment_method": "Midtrans",
+            "payment_status": "paid"
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid status"
+    },
+    "message": "Invalid status"
+}
+
+ +
+ POST + /tailors/{tailor}/book +

Membuat booking baru ke penjahit

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Path Parameters
+
    +
  • tailor - ID penjahit yang akan dibooking
  • +
+
Request Body
+
{
+    "appointment_date": "2023-05-15",
+    "appointment_time": "14:00",
+    "service_type": "Jahit Baru",
+    "category": "Atasan",
+    "design_photo": [file],
+    "notes": "Mohon dibuat sesuai ukuran",
+    "payment_method": "Midtrans"
+}
+
Validasi
+
    +
  • appointment_date - Wajib diisi, format tanggal (YYYY-MM-DD), harus tanggal sekarang atau setelahnya
  • +
  • appointment_time - Wajib diisi, format waktu (HH:MM)
  • +
  • service_type - Wajib diisi, nilai valid: "Perbaikan", "Jahit Baru"
  • +
  • category - Wajib diisi, nilai valid: "Atasan", "Bawahan", "Terusan"
  • +
  • design_photo - Wajib diisi, file gambar, maksimal 2MB
  • +
  • notes - Opsional, catatan tambahan
  • +
  • payment_method - Wajib diisi, metode pembayaran
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "booking": {
+            "id": 5,
+            "transaction_code": "TRX-005",
+            "customer_id": 1,
+            "tailor_id": 2,
+            "appointment_date": "2023-05-15",
+            "appointment_time": "14:00",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "design_photo": "design_photos/design5.jpg",
+            "notes": "Mohon dibuat sesuai ukuran",
+            "status": "reservasi",
+            "payment_status": "unpaid",
+            "payment_method": "Midtrans",
+            "created_at": "2023-05-05T10:00:00.000000Z",
+            "updated_at": "2023-05-05T10:00:00.000000Z"
+        },
+        "message": "Booking berhasil dibuat",
+        "next_steps": {
+            "payment": "Silakan lakukan pembayaran untuk mengkonfirmasi booking",
+            "cancellation": "Anda dapat membatalkan booking sebelum melakukan pembayaran"
+        }
+    },
+    "message": "Booking berhasil dibuat"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "appointment": ["Jadwal tidak tersedia. Penjahit sudah memiliki booking pada tanggal yang sama"]
+    },
+    "message": "Error validasi."
+}
+
+ +
+ POST + /bookings/{booking}/cancel +

Membatalkan booking

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • booking - ID booking yang akan dibatalkan
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "status": "dibatalkan",
+        "updated_at": "2023-05-05T11:00:00.000000Z"
+    },
+    "message": "Booking berhasil dibatalkan."
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "status": ["Booking tidak dapat dibatalkan karena sudah diproses"]
+    },
+    "message": "Error validasi."
+}
+
+
+ +
+

Penjahit

+ +
+ GET + /penjahit/dashboard +

Mendapatkan data dashboard penjahit

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 2,
+            "name": "Penjahit ABC",
+            "email": "tailor@example.com"
+        },
+        "stats": {
+            "total_bookings": 10,
+            "ongoing_bookings": 5,
+            "completed_bookings": 4,
+            "cancelled_bookings": 1,
+            "average_rating": 4.5
+        },
+        "recent_bookings": [
+            {
+                "id": 10,
+                "transaction_code": "TRX-010",
+                "customer_name": "John Doe",
+                "appointment_date": "2023-05-20",
+                "service_type": "Jahit Baru",
+                "status": "reservasi",
+                "created_at": "2023-05-10T10:00:00.000000Z"
+            }
+        ],
+        "earnings": {
+            "this_month": 750000,
+            "last_month": 500000,
+            "total": 1250000
+        }
+    },
+    "message": "Dashboard data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /penjahit/calendar/{month}/{year} +

Mendapatkan jadwal booking untuk bulan dan tahun tertentu

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • month - Bulan (1-12)
  • +
  • year - Tahun (format 4 digit, contoh: 2023)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "2023-05-01": {
+            "date": "2023-05-01",
+            "day": "01",
+            "day_name": "Senin",
+            "bookings": []
+        },
+        "2023-05-02": {
+            "date": "2023-05-02",
+            "day": "02",
+            "day_name": "Selasa",
+            "bookings": [
+                {
+                    "id": 1,
+                    "transaction_code": "TRX-001",
+                    "customer_name": "John Doe",
+                    "customer_phone": "08123456789",
+                    "appointment_time": "10:00",
+                    "service_type": "Jahit Baru",
+                    "category": "Atasan",
+                    "status": "dikonfirmasi"
+                }
+            ]
+        }
+    },
+    "message": "Calendar data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid date"
+    },
+    "message": "Invalid date"
+}
+
+ +
+ POST + /bookings/{booking}/accept +

Menerima booking dari pelanggan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan diterima
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "status": "dikonfirmasi",
+        "accepted_at": "2023-05-05T14:00:00.000000Z",
+        "updated_at": "2023-05-05T14:00:00.000000Z"
+    },
+    "message": "Booking berhasil dikonfirmasi"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Booking tidak dapat dikonfirmasi karena status sudah berubah"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /bookings/{booking}/reject +

Menolak booking dari pelanggan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan ditolak
  • +
+
Request Body
+
{
+    "rejection_reason": "Jadwal sudah penuh"
+}
+
Validasi
+
    +
  • rejection_reason - Wajib diisi, alasan penolakan
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "status": "dibatalkan",
+        "rejection_reason": "Jadwal sudah penuh",
+        "rejected_at": "2023-05-05T14:00:00.000000Z",
+        "updated_at": "2023-05-05T14:00:00.000000Z"
+    },
+    "message": "Booking berhasil ditolak"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "rejection_reason": ["Alasan penolakan wajib diisi"]
+    },
+    "message": "Error validasi."
+}
+
+ +
+ POST + /bookings/{booking}/payment +

Mengubah status pembayaran booking menjadi paid

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan diubah status pembayarannya
  • +
+
Request Body
+
{
+    "payment_status": "paid"
+}
+
Validasi
+
    +
  • payment_status - Wajib diisi, nilai valid: "paid" atau "success"
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "payment_status": "paid",
+        "updated_at": "2023-05-05T15:00:00.000000Z"
+    },
+    "message": "Status pembayaran berhasil diubah"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Unauthorized."
+}
+
+ +
+ POST + /bookings/{booking}/completion-payment +

Memproses pembayaran akhir dan mengatur tanggal pengambilan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan diproses pembayaran akhirnya
  • +
+
Request Body
+
{
+    "pickup_date": "2023-05-20"
+}
+
Validasi
+
    +
  • pickup_date - Wajib diisi, format tanggal (YYYY-MM-DD), harus tanggal sekarang atau setelahnya
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "payment_status": "paid",
+        "pickup_date": "2023-05-20",
+        "updated_at": "2023-05-05T16:00:00.000000Z"
+    },
+    "message": "Pembayaran akhir berhasil diproses"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid status",
+        "message": "Pembayaran hanya dapat dilakukan untuk pesanan yang sudah selesai"
+    },
+    "message": "Invalid status"
+}
+
+ +
+ GET + /penjahit/bookings +

Mendapatkan semua booking penjahit

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • status (optional) - Filter berdasarkan status (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 5,
+            "transaction_code": "TRX-005",
+            "customer_id": 1,
+            "appointment_date": "2023-05-15",
+            "appointment_time": "14:00",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "status": "dikonfirmasi",
+            "total_price": 150000,
+            "payment_status": "paid",
+            "created_at": "2023-05-05T10:00:00.000000Z",
+            "updated_at": "2023-05-05T15:00:00.000000Z",
+            "customer": {
+                "id": 1,
+                "name": "John Doe",
+                "phone_number": "08123456789"
+            }
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /penjahit/bookings/status/{status} +

Mendapatkan booking penjahit berdasarkan status

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • status - Status booking (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 5,
+            "transaction_code": "TRX-005",
+            "customer_name": "John Doe",
+            "customer_phone": "08123456789",
+            "appointment_date": "2023-05-15",
+            "service_type": "Jahit Baru",
+            "payment_status": "paid"
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid status"
+    },
+    "message": "Invalid status"
+}
+
+ +
+ GET + /penjahit/services +

Mendapatkan semua layanan penjahit

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "tailor_id": 2,
+            "name": "Jahit Kemeja",
+            "description": "Jasa jahit kemeja pria dan wanita",
+            "price": 150000,
+            "is_available": true,
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        }
+    ],
+    "message": "Services retrieved successfully"
+}
+
+ +
+ POST + /penjahit/services +

Menambahkan layanan baru

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "name": "Jahit Jas",
+    "description": "Jasa pembuatan jas pria berkualitas tinggi",
+    "price": 500000
+}
+
Validasi
+
    +
  • name - Wajib diisi, nama layanan
  • +
  • description - Wajib diisi, deskripsi layanan
  • +
  • price - Wajib diisi, harga layanan (angka)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 2,
+        "tailor_id": 2,
+        "name": "Jahit Jas",
+        "description": "Jasa pembuatan jas pria berkualitas tinggi",
+        "price": 500000,
+        "is_available": true,
+        "created_at": "2023-05-05T10:00:00.000000Z",
+        "updated_at": "2023-05-05T10:00:00.000000Z"
+    },
+    "message": "Service created successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "price": ["Harga harus berupa angka"]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ GET + /penjahit/gallery +

Mendapatkan semua galeri penjahit

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "tailor_id": 2,
+            "title": "Kemeja Batik",
+            "description": "Kemeja batik pesanan pelanggan",
+            "photo_path": "gallery_photos/kemeja_batik.jpg",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        }
+    ],
+    "message": "Gallery items retrieved successfully"
+}
+
+ +
+ POST + /penjahit/gallery +

Menambahkan item galeri baru

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Request Body
+
{
+    "title": "Jas Pernikahan",
+    "description": "Jas pernikahan custom pesanan pelanggan",
+    "photo": [file]
+}
+
Validasi
+
    +
  • title - Wajib diisi, judul item galeri
  • +
  • description - Wajib diisi, deskripsi item galeri
  • +
  • photo - Wajib diisi, file gambar, maksimal 2MB
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 2,
+        "tailor_id": 2,
+        "title": "Jas Pernikahan",
+        "description": "Jas pernikahan custom pesanan pelanggan",
+        "photo_path": "gallery_photos/jas_pernikahan.jpg",
+        "created_at": "2023-05-05T10:00:00.000000Z",
+        "updated_at": "2023-05-05T10:00:00.000000Z"
+    },
+    "message": "Gallery item created successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "photo": ["File harus berupa gambar dengan ukuran maksimal 2MB"]
+    },
+    "message": "Validation Error."
+}
+
+
+ +
+

Admin

+ +
+ GET + /admin/dashboard +

Mendapatkan data dashboard admin

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "stats": {
+            "total_users": {
+                "customers": 50,
+                "tailors": 20,
+                "admins": 2
+            },
+            "bookings": {
+                "total": 100,
+                "ongoing": 40,
+                "completed": 55,
+                "cancelled": 5
+            },
+            "revenue": {
+                "this_month": 5000000,
+                "last_month": 4500000,
+                "total": 15000000
+            },
+            "ratings": {
+                "average": 4.7,
+                "count": 75
+            }
+        },
+        "recent_bookings": [
+            {
+                "id": 10,
+                "transaction_code": "TRX-010",
+                "customer_name": "John Doe",
+                "tailor_name": "Penjahit ABC",
+                "service_type": "Jahit Baru",
+                "status": "diproses",
+                "total_price": 150000,
+                "created_at": "2023-05-10T10:00:00.000000Z"
+            }
+        ],
+        "recent_users": [
+            {
+                "id": 70,
+                "name": "Jane Smith",
+                "role": "pelanggan",
+                "created_at": "2023-05-10T10:00:00.000000Z"
+            }
+        ]
+    },
+    "message": "Dashboard data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized access"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /customers +

Mendapatkan semua data pelanggan

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • search (optional) - Mencari berdasarkan nama atau email
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "profile_photo": "profile_photos/user1.jpg",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "bookings_count": 5
+        }
+    ],
+    "message": "Customers retrieved successfully"
+}
+
+
+ +
+

Wallet & Withdrawal

+ +
+ GET + /wallet +

Mendapatkan informasi wallet pengguna

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "balance": 1000000.00,
+        "transactions": [
+            {
+                "id": 1,
+                "type": "credit",
+                "amount": 500000.00,
+                "description": "Pembayaran booking #TRX-001",
+                "status": "success",
+                "created_at": "2024-05-03T10:00:00.000000Z",
+                "booking": {
+                    "id": 1,
+                    "transaction_code": "TRX-001",
+                    "service_type": "jahit",
+                    "category": "baju"
+                }
+            }
+        ]
+    },
+    "message": "Wallet information retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+    }
+}
+
+ +
+ GET + /customers +

Mendapatkan semua data pelanggan

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • search (optional) - Mencari berdasarkan nama atau email
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "profile_photo": "profile_photos/user1.jpg",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "bookings_count": 5
+        }
+    ],
+    "message": "Customers retrieved successfully"
+}
+
+
+
+ +
+

File & Media

+
+
+
+
+ + + + + diff --git a/TA_API/resources/views/api-docs.blade.php b/TA_API/resources/views/api-docs.blade.php new file mode 100644 index 0000000..4921b66 --- /dev/null +++ b/TA_API/resources/views/api-docs.blade.php @@ -0,0 +1,2489 @@ + + + + + + + Dokumentasi API Project Jahit + + + + + + + +
+
+ + +
+
+

Pendahuluan

+

Project Jahit adalah platform yang menghubungkan pelanggan dengan penjahit. API ini menyediakan + endpoint untuk mengelola registrasi pengguna, pencarian penjahit, pemesanan jasa, manajemen + galeri dan layanan penjahit, serta sistem rating.

+ +

Base URL

+
http://localhost:8000/api
+
+ +
+

Autentikasi

+

API ini menggunakan Laravel Sanctum untuk autentikasi. Token akan diberikan setelah login dan + harus disertakan dalam header setiap permintaan ke endpoint yang terproteksi.

+ +

Format Header

+
Authorization: Bearer {token}
+
+ +
+

Role & Hak Akses

+

Sistem memiliki 3 role pengguna:

+
    +
  • admin - Administrator platform
  • +
  • penjahit - Penjahit/Penyedia jasa
  • +
  • pelanggan - Pelanggan/Pengguna jasa
  • +
+
+ +
+

Endpoint API

+ +
+

Endpoint Publik

+ +
+ GET + /test +

Tes koneksi API

+
Response
+
{
+  "message": "API is working"
+}
+
+ +
+ GET + /specializations +

Mendapatkan semua spesialisasi penjahit

+
+ +
+ GET + /tailors/search?specialization={id} +

Mencari penjahit berdasarkan spesialisasi

+
+ +
+ GET + /tailors/{id} +

Mendapatkan detail informasi penjahit

+
+
+ +
+

Autentikasi

+ +
+ POST + /pelanggan/register +

Registrasi akun pelanggan baru

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "name": "John Doe",
+    "email": "john@example.com",
+    "password": "password123",
+    "password_confirmation": "password123",
+    "phone_number": "08123456789",
+    "address": "Jl. Example No. 123"
+}
+
Validasi
+
    +
  • name - Wajib diisi, nama lengkap pengguna
  • +
  • email - Wajib diisi, format email, harus unik
  • +
  • password - Wajib diisi, minimal 8 karakter
  • +
  • password_confirmation - Wajib diisi, harus sama dengan password
  • +
  • phone_number - Wajib diisi, nomor telepon
  • +
  • address - Wajib diisi, alamat lengkap
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "role": "pelanggan",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Pendaftaran berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "email": ["Email sudah digunakan."],
+        "password": ["Password minimal harus 8 karakter."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /pelanggan/login +

Login sebagai pelanggan

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "email": "john@example.com",
+    "password": "password123"
+}
+
Validasi
+
    +
  • email - Wajib diisi, format email
  • +
  • password - Wajib diisi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "role": "pelanggan",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Login berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Email atau password tidak valid"
+    },
+    "message": "Authentication Error."
+}
+
+ +
+ POST + /penjahit/register +

Registrasi akun penjahit baru

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "name": "John Doe",
+    "email": "tailor@example.com",
+    "password": "password123",
+    "password_confirmation": "password123",
+    "phone_number": "08123456789",
+    "address": "Jl. Example No. 123",
+    "shop_description": "Jasa jahit profesional dengan pelayanan terbaik",
+    "specializations": [1, 2, 3]
+}
+
Validasi
+
    +
  • name - Wajib diisi, nama lengkap penjahit
  • +
  • email - Wajib diisi, format email, harus unik
  • +
  • password - Wajib diisi, minimal 8 karakter
  • +
  • password_confirmation - Wajib diisi, harus sama dengan password
  • +
  • phone_number - Wajib diisi, nomor telepon
  • +
  • address - Wajib diisi, alamat lengkap
  • +
  • shop_description - Wajib diisi, deskripsi toko/jasa
  • +
  • specializations - Wajib diisi, array ID spesialisasi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 2,
+            "name": "John Doe",
+            "email": "tailor@example.com",
+            "role": "penjahit",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "shop_description": "Jasa jahit profesional dengan pelayanan terbaik",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z",
+            "specializations": [
+                {
+                    "id": 1,
+                    "name": "Kemeja"
+                },
+                {
+                    "id": 2,
+                    "name": "Gaun"
+                },
+                {
+                    "id": 3,
+                    "name": "Celana"
+                }
+            ]
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Pendaftaran berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "email": ["Email sudah digunakan."],
+        "specializations": ["Spesialisasi wajib diisi."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /penjahit/login +

Login sebagai penjahit

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "email": "tailor@example.com",
+    "password": "password123"
+}
+
Validasi
+
    +
  • email - Wajib diisi, format email
  • +
  • password - Wajib diisi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 2,
+            "name": "John Doe",
+            "email": "tailor@example.com",
+            "role": "penjahit",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "shop_description": "Jasa jahit profesional dengan pelayanan terbaik",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Login berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Email atau password tidak valid"
+    },
+    "message": "Authentication Error."
+}
+
+ +
+ POST + /admin/login +

Login sebagai admin

+
Headers
+
Content-Type: application/json
+
Request Body
+
{
+    "email": "admin@example.com",
+    "password": "admin123"
+}
+
Validasi
+
    +
  • email - Wajib diisi, format email
  • +
  • password - Wajib diisi
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 3,
+            "name": "Admin",
+            "email": "admin@example.com",
+            "role": "admin",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        },
+        "token": "1|laravel_sanctum_token..."
+    },
+    "message": "Login berhasil"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Email atau password tidak valid"
+    },
+    "message": "Authentication Error."
+}
+
+ +
+ POST + /logout +

Logout pengguna (invalidasi token)

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {},
+    "message": "Berhasil logout"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthenticated"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /email/verification-notification +

Mengirim ulang email verifikasi

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {},
+    "message": "Email verifikasi telah dikirim"
+}
+
+
+ +
+

Profil

+ +
+ GET + /profile +

Mendapatkan informasi profil pengguna

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "name": "John Doe",
+        "email": "john@example.com",
+        "role": "pelanggan",
+        "phone_number": "08123456789",
+        "address": "Jl. Example No. 123",
+        "profile_photo": "profile_photos/user1.jpg",
+        "created_at": "2023-05-01T10:00:00.000000Z",
+        "updated_at": "2023-05-01T10:00:00.000000Z"
+    },
+    "message": "Profil berhasil ditemukan"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthenticated"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /profile +

Mengupdate informasi profil pengguna

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "name": "John Doe Updated",
+    "phone_number": "087654321",
+    "address": "Jl. Updated No. 456",
+    "shop_description": "Deskripsi toko yang diupdate" // khusus penjahit
+}
+
Validasi
+
    +
  • name - Opsional, nama baru pengguna
  • +
  • phone_number - Opsional, nomor telepon baru
  • +
  • address - Opsional, alamat baru
  • +
  • shop_description - Opsional, deskripsi toko baru (hanya untuk penjahit)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "name": "John Doe Updated",
+        "email": "john@example.com",
+        "role": "pelanggan",
+        "phone_number": "087654321",
+        "address": "Jl. Updated No. 456",
+        "created_at": "2023-05-01T10:00:00.000000Z",
+        "updated_at": "2023-05-02T10:00:00.000000Z"
+    },
+    "message": "Profil berhasil diupdate"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "phone_number": ["Format nomor telepon tidak valid"]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /profile/photo +

Mengupload foto profil

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Request Body
+
{
+    "profile_photo": [file]
+}
+
Validasi
+
    +
  • profile_photo - Wajib diisi, file gambar, maksimal 2MB
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "name": "John Doe",
+        "profile_photo": "profile_photos/user1_updated.jpg"
+    },
+    "message": "Foto profil berhasil diupload"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "profile_photo": ["File harus berupa gambar dengan ukuran maksimal 2MB"]
+    },
+    "message": "Validation Error."
+}
+
+
+ +
+

Pelanggan

+ +
+ GET + /dashboard +

Mendapatkan data dashboard pelanggan

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "phone_number": "08123456789"
+        },
+        "bookings_count": {
+            "total": 5,
+            "ongoing": 2,
+            "completed": 3
+        },
+        "latest_bookings": [
+            {
+                "id": 3,
+                "transaction_code": "TRX-003",
+                "tailor_name": "Penjahit ABC",
+                "category": "Atasan",
+                "service_type": "Jahit Baru",
+                "status": "diproses",
+                "appointment_date": "2023-05-10"
+            }
+        ]
+    },
+    "message": "Dashboard data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /bookings/customer +

Mendapatkan semua booking yang dilakukan pelanggan

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • status (optional) - Filter berdasarkan status (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "transaction_code": "TRX-001",
+            "customer_id": 1,
+            "tailor_id": 2,
+            "appointment_date": "2023-05-05",
+            "appointment_time": "10:00",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "design_photo": "design_photos/design1.jpg",
+            "notes": "Mohon dibuat sesuai ukuran",
+            "status": "selesai",
+            "total_price": 150000,
+            "payment_status": "paid",
+            "payment_method": "Midtrans",
+            "completed_at": "2023-05-10T14:00:00.000000Z",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-10T14:00:00.000000Z",
+            "tailor": {
+                "id": 2,
+                "name": "Penjahit ABC",
+                "profile_photo": "profile_photos/tailor1.jpg",
+                "address": "Jl. Penjahit No. 123"
+            },
+            "rating": {
+                "id": 1,
+                "rating": 5,
+                "review": "Sangat puas dengan hasilnya"
+            }
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /bookings/customer/status/{status} +

Mendapatkan booking pelanggan berdasarkan status

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • status - Status booking (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "transaction_code": "TRX-001",
+            "tailor_name": "Penjahit ABC",
+            "tailor_photo": "profile_photos/tailor1.jpg",
+            "appointment_date": "2023-05-05",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "payment_method": "Midtrans",
+            "payment_status": "paid"
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid status"
+    },
+    "message": "Invalid status"
+}
+
+ +
+ POST + /tailors/{tailor}/book +

Membuat booking baru ke penjahit

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Path Parameters
+
    +
  • tailor - ID penjahit yang akan dibooking
  • +
+
Request Body
+
{
+    "appointment_date": "2023-05-15",
+    "appointment_time": "14:00",
+    "service_type": "Jahit Baru",
+    "category": "Atasan",
+    "design_photo": [file],
+    "notes": "Mohon dibuat sesuai ukuran",
+    "payment_method": "Midtrans"
+}
+
Validasi
+
    +
  • appointment_date - Wajib diisi, format tanggal (YYYY-MM-DD), harus tanggal sekarang atau setelahnya
  • +
  • appointment_time - Wajib diisi, format waktu (HH:MM). Setiap booking memiliki durasi 2 jam. Jika ada booking pada jam 08:00, slot 08:00-10:00 akan terisi
  • +
  • service_type - Wajib diisi, nilai valid: "Perbaikan", "Jahit Baru"
  • +
  • category - Wajib diisi, nilai valid: "Atasan", "Bawahan", "Terusan"
  • +
  • design_photo - Wajib diisi, file gambar, maksimal 2MB
  • +
  • notes - Opsional, catatan tambahan
  • +
  • payment_method - Wajib diisi, metode pembayaran
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "booking": {
+            "id": 5,
+            "transaction_code": "TRX-005",
+            "customer_id": 1,
+            "tailor_id": 2,
+            "appointment_date": "2023-05-15",
+            "appointment_time": "14:00",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "design_photo": "design_photos/design5.jpg",
+            "notes": "Mohon dibuat sesuai ukuran",
+            "status": "reservasi",
+            "payment_status": "unpaid",
+            "payment_method": "Midtrans",
+            "created_at": "2023-05-05T10:00:00.000000Z",
+            "updated_at": "2023-05-05T10:00:00.000000Z"
+        },
+        "message": "Booking berhasil dibuat",
+        "next_steps": {
+            "payment": "Silakan lakukan pembayaran untuk mengkonfirmasi booking",
+            "cancellation": "Anda dapat membatalkan booking sebelum melakukan pembayaran"
+        }
+    },
+    "message": "Booking berhasil dibuat"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "appointment": ["Jadwal tidak tersedia. Penjahit sudah memiliki booking pada waktu tersebut (durasi 2 jam)"]
+    },
+    "message": "Error validasi."
+}
+
+ +
+ POST + /bookings/{booking}/cancel +

Membatalkan booking

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • booking - ID booking yang akan dibatalkan
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "status": "dibatalkan",
+        "updated_at": "2023-05-05T11:00:00.000000Z"
+    },
+    "message": "Booking berhasil dibatalkan."
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "status": ["Booking tidak dapat dibatalkan karena sudah diproses"]
+    },
+    "message": "Error validasi."
+}
+
+
+ +
+

Penjahit

+ +
+ GET + /penjahit/dashboard +

Mendapatkan data dashboard penjahit

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "user": {
+            "id": 2,
+            "name": "Penjahit ABC",
+            "email": "tailor@example.com"
+        },
+        "stats": {
+            "total_bookings": 10,
+            "ongoing_bookings": 5,
+            "completed_bookings": 4,
+            "cancelled_bookings": 1,
+            "average_rating": 4.5
+        },
+        "recent_bookings": [
+            {
+                "id": 10,
+                "transaction_code": "TRX-010",
+                "customer_name": "John Doe",
+                "appointment_date": "2023-05-20",
+                "service_type": "Jahit Baru",
+                "status": "reservasi",
+                "created_at": "2023-05-10T10:00:00.000000Z"
+            }
+        ],
+        "earnings": {
+            "this_month": 750000,
+            "last_month": 500000,
+            "total": 1250000
+        }
+    },
+    "message": "Dashboard data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /penjahit/calendar/{month}/{year} +

Mendapatkan jadwal booking untuk bulan dan tahun tertentu

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • month - Bulan (1-12)
  • +
  • year - Tahun (format 4 digit, contoh: 2023)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "2023-05-01": {
+            "date": "2023-05-01",
+            "day": "01",
+            "day_name": "Senin",
+            "bookings": []
+        },
+        "2023-05-02": {
+            "date": "2023-05-02",
+            "day": "02",
+            "day_name": "Selasa",
+            "bookings": [
+                {
+                    "id": 1,
+                    "transaction_code": "TRX-001",
+                    "customer_name": "John Doe",
+                    "customer_phone": "08123456789",
+                    "appointment_time": "10:00",
+                    "appointment_end_time": "12:00", // Durasi 2 jam
+                    "service_type": "Jahit Baru",
+                    "category": "Atasan",
+                    "status": "dikonfirmasi"
+                }
+            ]
+        }
+    },
+    "message": "Calendar data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid date"
+    },
+    "message": "Invalid date"
+}
+
+ +
+ POST + /bookings/{booking}/accept +

Menerima booking dari pelanggan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan diterima
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "status": "dikonfirmasi",
+        "accepted_at": "2023-05-05T14:00:00.000000Z",
+        "updated_at": "2023-05-05T14:00:00.000000Z"
+    },
+    "message": "Booking berhasil dikonfirmasi"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Booking tidak dapat dikonfirmasi karena status sudah berubah"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /bookings/{booking}/reject +

Menolak booking dari pelanggan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan ditolak
  • +
+
Request Body
+
{
+    "rejection_reason": "Jadwal sudah penuh"
+}
+
Validasi
+
    +
  • rejection_reason - Wajib diisi, alasan penolakan
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "status": "dibatalkan",
+        "rejection_reason": "Jadwal sudah penuh",
+        "rejected_at": "2023-05-05T14:00:00.000000Z",
+        "updated_at": "2023-05-05T14:00:00.000000Z"
+    },
+    "message": "Booking berhasil ditolak"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "rejection_reason": ["Alasan penolakan wajib diisi"]
+    },
+    "message": "Error validasi."
+}
+
+ +
+ POST + /bookings/{booking}/payment +

Mengubah status pembayaran booking menjadi paid

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan diubah status pembayarannya
  • +
+
Request Body
+
{
+    "payment_status": "paid"
+}
+
Validasi
+
    +
  • payment_status - Wajib diisi, nilai valid: "paid" atau "success"
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "payment_status": "paid",
+        "updated_at": "2023-05-05T15:00:00.000000Z"
+    },
+    "message": "Status pembayaran berhasil diubah"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Unauthorized."
+}
+
+ +
+ POST + /bookings/{booking}/completion-payment +

Memproses pembayaran akhir dan mengatur tanggal pengambilan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • booking - ID booking yang akan diproses pembayaran akhirnya
  • +
+
Request Body
+
{
+    "pickup_date": "2023-05-20"
+}
+
Validasi
+
    +
  • pickup_date - Wajib diisi, format tanggal (YYYY-MM-DD), harus tanggal sekarang atau setelahnya
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 5,
+        "payment_status": "paid",
+        "pickup_date": "2023-05-20",
+        "updated_at": "2023-05-05T16:00:00.000000Z"
+    },
+    "message": "Pembayaran akhir berhasil diproses"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid status",
+        "message": "Pembayaran hanya dapat dilakukan untuk pesanan yang sudah selesai"
+    },
+    "message": "Invalid status"
+}
+
+ +
+ GET + /penjahit/bookings +

Mendapatkan semua booking penjahit

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • status (optional) - Filter berdasarkan status (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 5,
+            "transaction_code": "TRX-005",
+            "customer_id": 1,
+            "appointment_date": "2023-05-15",
+            "appointment_time": "14:00",
+            "service_type": "Jahit Baru",
+            "category": "Atasan",
+            "status": "dikonfirmasi",
+            "total_price": 150000,
+            "payment_status": "paid",
+            "created_at": "2023-05-05T10:00:00.000000Z",
+            "updated_at": "2023-05-05T15:00:00.000000Z",
+            "customer": {
+                "id": 1,
+                "name": "John Doe",
+                "phone_number": "08123456789"
+            }
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /penjahit/bookings/status/{status} +

Mendapatkan booking penjahit berdasarkan status

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • status - Status booking (reservasi, dikonfirmasi, diproses, selesai, dibatalkan)
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 5,
+            "transaction_code": "TRX-005",
+            "customer_name": "John Doe",
+            "customer_phone": "08123456789",
+            "appointment_date": "2023-05-15",
+            "service_type": "Jahit Baru",
+            "payment_status": "paid"
+        }
+    ],
+    "message": "Booking list retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid status"
+    },
+    "message": "Invalid status"
+}
+
+ +
+ GET + /penjahit/services +

Mendapatkan semua layanan penjahit

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "tailor_id": 2,
+            "name": "Jahit Kemeja",
+            "description": "Jasa jahit kemeja pria dan wanita",
+            "price": 150000,
+            "is_available": true,
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        }
+    ],
+    "message": "Services retrieved successfully"
+}
+
+ +
+ POST + /penjahit/services +

Menambahkan layanan baru

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "name": "Jahit Jas",
+    "description": "Jasa pembuatan jas pria berkualitas tinggi",
+    "price": 500000
+}
+
Validasi
+
    +
  • name - Wajib diisi, nama layanan
  • +
  • description - Wajib diisi, deskripsi layanan
  • +
  • price - Wajib diisi, harga layanan (angka)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 2,
+        "tailor_id": 2,
+        "name": "Jahit Jas",
+        "description": "Jasa pembuatan jas pria berkualitas tinggi",
+        "price": 500000,
+        "is_available": true,
+        "created_at": "2023-05-05T10:00:00.000000Z",
+        "updated_at": "2023-05-05T10:00:00.000000Z"
+    },
+    "message": "Service created successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "price": ["Harga harus berupa angka"]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ GET + /penjahit/gallery +

Mendapatkan semua galeri penjahit

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "tailor_id": 2,
+            "title": "Kemeja Batik",
+            "description": "Kemeja batik pesanan pelanggan",
+            "photo_path": "gallery_photos/kemeja_batik.jpg",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "updated_at": "2023-05-01T10:00:00.000000Z"
+        }
+    ],
+    "message": "Gallery items retrieved successfully"
+}
+
+ +
+ POST + /penjahit/gallery +

Menambahkan item galeri baru

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Request Body
+
{
+    "title": "Jas Pernikahan",
+    "description": "Jas pernikahan custom pesanan pelanggan",
+    "photo": [file]
+}
+
Validasi
+
    +
  • title - Wajib diisi, judul item galeri
  • +
  • description - Wajib diisi, deskripsi item galeri
  • +
  • photo - Wajib diisi, file gambar, maksimal 2MB
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 2,
+        "tailor_id": 2,
+        "title": "Jas Pernikahan",
+        "description": "Jas pernikahan custom pesanan pelanggan",
+        "photo_path": "gallery_photos/jas_pernikahan.jpg",
+        "created_at": "2023-05-05T10:00:00.000000Z",
+        "updated_at": "2023-05-05T10:00:00.000000Z"
+    },
+    "message": "Gallery item created successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "photo": ["File harus berupa gambar dengan ukuran maksimal 2MB"]
+    },
+    "message": "Validation Error."
+}
+
+
+ +
+

Admin

+ +
+ GET + /admin/dashboard +

Mendapatkan data dashboard admin

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "stats": {
+            "total_users": {
+                "customers": 50,
+                "tailors": 20,
+                "admins": 2
+            },
+            "bookings": {
+                "total": 100,
+                "ongoing": 40,
+                "completed": 55,
+                "cancelled": 5
+            },
+            "revenue": {
+                "this_month": 5000000,
+                "last_month": 4500000,
+                "total": 15000000
+            },
+            "ratings": {
+                "average": 4.7,
+                "count": 75
+            }
+        },
+        "recent_bookings": [
+            {
+                "id": 10,
+                "transaction_code": "TRX-010",
+                "customer_name": "John Doe",
+                "tailor_name": "Penjahit ABC",
+                "service_type": "Jahit Baru",
+                "status": "diproses",
+                "total_price": 150000,
+                "created_at": "2023-05-10T10:00:00.000000Z"
+            }
+        ],
+        "recent_users": [
+            {
+                "id": 70,
+                "name": "Jane Smith",
+                "role": "pelanggan",
+                "created_at": "2023-05-10T10:00:00.000000Z"
+            }
+        ]
+    },
+    "message": "Dashboard data retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized access"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /customers +

Mendapatkan semua data pelanggan

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • search (optional) - Mencari berdasarkan nama atau email
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "name": "John Doe",
+            "email": "john@example.com",
+            "phone_number": "08123456789",
+            "address": "Jl. Example No. 123",
+            "profile_photo": "profile_photos/user1.jpg",
+            "created_at": "2023-05-01T10:00:00.000000Z",
+            "bookings_count": 5
+        }
+    ],
+    "message": "Customers retrieved successfully"
+}
+
+ +
+ GET + /admin/withdrawals/pending +

Mendapatkan daftar permintaan penarikan dana yang perlu diproses

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{\n    "success": true,\n    "data": [\n        {\n            "id": 1,\n            "amount": 500000.00,\n            "status": "pending",\n            "created_at": "2024-05-03T10:00:00.000000Z",\n            "wallet": {\n                "user": {\n                    "id": 1,\n                    "name": "John Doe",\n                    "email": "john@example.com"\n                }\n            },\n            "bank_account": {\n                "bank_name": "BCA",\n                "account_number": "1234567890",\n                "account_holder_name": "John Doe"\n            }\n        }\n    ],\n    "message": "Pending withdrawals retrieved successfully"\n}
+
+ +
+ GET + /admin/bank-accounts/pending +

Mendapatkan daftar rekening bank yang perlu diverifikasi

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{\n    "success": true,\n    "data": [\n        {\n            "id": 1,\n            "user_id": 2,\n            "bank_name": "BCA",\n            "account_number": "1234567890",
+                "account_holder_name": "John Doe",\n            "status": "pending",\n            "created_at": "2024-05-03T10:00:00.000000Z",\n            "updated_at": "2024-05-03T10:00:00.000000Z",\n            "user": {\n                "id": 2,\n                "name": "John Doe",\n                "email": "john@example.com",\n                "role": "penjahit"\n            }\n        }\n    ],\n    "message": "Pending bank accounts retrieved successfully"\n}
+
+ +
+ POST + /admin/withdrawals/{withdrawal}/process +

Memproses permintaan penarikan (approve/reject)

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Path Parameters
+
    +
  • withdrawal - ID permintaan penarikan
  • +
+
Request Body
+
{
+    "status": "completed", // atau "rejected"
+    "rejection_reason": "", // wajib diisi jika status = "rejected"
+    "proof_of_payment": [file] // wajib diupload jika status = "completed"
+}
+
Validasi
+
    +
  • status - Wajib diisi, nilai yang valid: "completed" atau "rejected"
  • +
  • rejection_reason - Wajib diisi jika status = "rejected"
  • +
  • proof_of_payment - Wajib diisi jika status = "completed", file bukti pembayaran
  • +
+
Response (Completed)
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "wallet_id": 1,
+        "bank_account_id": 1,
+        "amount": 500000.00,
+        "status": "completed",
+        "rejection_reason": null,
+        "proof_of_payment": "proof_of_payments/withdrawal_1_proof.jpg",
+        "processed_at": "2024-05-03T10:30:00.000000Z",
+        "created_at": "2024-05-03T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:30:00.000000Z"
+    },
+    "message": "Withdrawal completed successfully"
+}
+
Response (Rejected)
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "wallet_id": 1,
+        "bank_account_id": 1,
+        "amount": 500000.00,
+        "status": "rejected",
+        "rejection_reason": "Informasi rekening tidak valid",
+        "proof_of_payment": null,
+        "processed_at": "2024-05-03T10:30:00.000000Z",
+        "created_at": "2024-05-03T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:30:00.000000Z"
+    },
+    "message": "Withdrawal rejected successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "status": ["The status field is required."],
+        "rejection_reason": ["The rejection reason field is required when status is rejected."],
+        "proof_of_payment": ["The proof of payment field is required when status is completed."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+

Wallet & Withdrawal

+ +

Midtrans Payment

+ +
+ POST + /bookings/{booking}/midtrans/pay +

Memulai proses pembayaran Midtrans

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • booking - ID booking yang akan dibayar
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "snap_token": "66e4fa55-fdac-4ef9-91b5-733b97d1b862",
+        "redirect_url": "https://app.sandbox.midtrans.com/snap/v2/vtweb/66e4fa55-fdac-4ef9-91b5-733b97d1b862",
+        "booking": {
+            "id": 1,
+            "transaction_code": "TRX-20240503-A1B2C3",
+            "total_price": 150000,
+            "status": "selesai"
+        }
+    },
+    "message": "Token pembayaran berhasil dibuat"
+}
+
+ +
+ GET + /bookings/{booking}/payment-status +

Memeriksa status pembayaran

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • booking - ID booking yang akan diperiksa status pembayarannya
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "booking_id": 1,
+        "transaction_code": "TRX-20240503-A1B2C3",
+        "payment_status": "pending",
+        "payment_method": "bank_transfer",
+        "total_price": 150000,
+        "status": "selesai",
+        "midtrans_snap_token": "66e4fa55-fdac-4ef9-91b5-733b97d1b862"
+    },
+    "message": "Status pembayaran berhasil diambil"
+}
+
+ +
+ POST + /bookings/{booking}/payment-status/check +

Memeriksa dan mengupdate status pembayaran secara manual

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • booking - ID booking yang akan diupdate status pembayarannya
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "booking_id": 1,
+        "transaction_code": "TRX-20240503-A1B2C3",
+        "payment_status": "paid",
+        "payment_method": "bank_transfer",
+        "total_price": 150000,
+        "status": "selesai",
+        "midtrans_status": "settlement",
+        "midtrans_snap_token": "66e4fa55-fdac-4ef9-91b5-733b97d1b862"
+    },
+    "message": "Status pembayaran berhasil diperbarui"
+}
+
+ +
+ GET + /wallet +

Mendapatkan informasi wallet

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "balance": 1000000.00,
+        "pending_withdrawals": 300000.00,
+        "available_balance": 700000.00,
+        "transactions": [
+            {
+                "id": 1,
+                "type": "credit",
+                "amount": 500000.00,
+                "description": "Pembayaran booking #TRX-001",
+                "status": "success",
+                "created_at": "2024-05-03T10:00:00.000000Z",
+                "booking": {
+                    "id": 1,
+                    "transaction_code": "TRX-001",
+                    "service_type": "jahit",
+                    "category": "baju"
+                }
+            }
+        ]
+    },
+    "message": "Wallet information retrieved successfully"
+}
+
Catatan
+
    +
  • balance - Total saldo dalam wallet
  • +
  • pending_withdrawals - Total semua penarikan yang masih dalam status "pending" atau "processing"
  • +
  • available_balance - Saldo yang tersedia untuk penarikan (balance - pending_withdrawals)
  • +
+
+ +
+ GET + /bank-accounts +

Mendapatkan daftar rekening bank penjahit

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "user_id": 2,
+            "bank_name": "BCA",
+            "account_number": "1234567890",
+            "account_holder_name": "John Doe",
+            "status": "active",
+            "rejection_reason": null,
+            "verified_at": "2024-05-03T10:00:00.000000Z",
+            "created_at": "2024-05-03T09:00:00.000000Z",
+            "updated_at": "2024-05-03T10:00:00.000000Z"
+        }
+    ],
+    "message": "Bank accounts retrieved successfully"
+}
+
+ +
+ POST + /bank-accounts +

Mendaftarkan rekening bank baru

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "bank_name": "BCA",
+    "account_number": "1234567890",
+    "account_holder_name": "John Doe"
+}
+
Validasi
+
    +
  • bank_name - Wajib diisi, nama bank
  • +
  • account_number - Wajib diisi, nomor rekening
  • +
  • account_holder_name - Wajib diisi, nama pemilik rekening
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "user_id": 2,
+        "bank_name": "BCA",
+        "account_number": "1234567890",
+        "account_holder_name": "John Doe",
+        "status": "pending",
+        "created_at": "2024-05-03T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:00:00.000000Z"
+    },
+    "message": "Bank account registered successfully"
+}
+
+ +
+ POST + /withdrawals +

Membuat permintaan penarikan dana

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "bank_account_id": 1,
+    "amount": 500000
+}
+
Validasi
+
    +
  • bank_account_id - Wajib diisi, ID rekening bank yang sudah terverifikasi
  • +
  • amount - Wajib diisi, jumlah penarikan (minimal 10000)
  • +
  • Jumlah penarikan harus kurang dari atau sama dengan saldo tersedia (available_balance)
  • +
  • Saldo tersedia dihitung dari: saldo total (balance) dikurangi total penarikan tertunda (pending_withdrawals)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "withdrawal": {
+            "id": 1,
+            "wallet_id": 1,
+            "bank_account_id": 1,
+            "amount": 500000.00,
+            "status": "pending",
+            "created_at": "2024-05-03T10:00:00.000000Z",
+            "updated_at": "2024-05-03T10:00:00.000000Z"
+        },
+        "wallet": {
+            "balance": 1000000.00,
+            "pending_withdrawals": 500000.00,
+            "available_balance": 500000.00
+        }
+    },
+    "message": "Withdrawal request submitted successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "balance": 1000000.00,
+        "pending_withdrawals": 800000.00,
+        "available_balance": 200000.00,
+        "requested_amount": 500000.00
+    },
+    "message": "Insufficient available balance."
+}
+
+ +
+ GET + /withdrawals +

Mendapatkan riwayat penarikan dana

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • status (optional) - Filter berdasarkan status penarikan. Nilai yang diperbolehkan: "pending", "processing", "completed", "rejected"
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "amount": 500000.00,
+            "status": "completed",
+            "created_at": "2024-05-03T10:00:00.000000Z",
+            "processed_at": "2024-05-03T11:00:00.000000Z",
+            "bank_account": {
+                "bank_name": "BCA",
+                "account_number": "1234567890",
+                "account_holder_name": "John Doe"
+            }
+        }
+    ],
+    "message": "Withdrawal history retrieved successfully"
+}
+
+ +

Manajemen Rekening Bank

+ +
+ POST + /admin/bank-accounts/{bankAccount}/verify +

Memverifikasi akun bank

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • bankAccount - ID akun bank
  • +
+
Request Body
+
{
+    "status": "active", // atau "rejected"
+    "rejection_reason": null // wajib diisi jika status = "rejected", boleh null jika status = "active"
+}
+
Validasi
+
    +
  • status - Wajib diisi, nilai yang valid: "active" atau "rejected"
  • +
  • rejection_reason - Wajib diisi jika status = "rejected", boleh null jika status = "active"
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "user_id": 2,
+        "bank_name": "BCA",
+        "account_number": "1234567890",
+        "account_holder_name": "John Doe",
+        "status": "active",
+        "rejection_reason": null,
+        "verified_at": "2024-05-03T10:00:00.000000Z",
+        "created_at": "2024-05-02T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:00:00.000000Z"
+    },
+    "message": "Bank account verification completed"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "status": ["The status field must be one of: active, rejected."],
+        "rejection_reason": ["The rejection reason field is required when status is rejected."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ GET + /admin/bank-accounts/verified +

Mendapatkan riwayat akun bank yang sudah diverifikasi (disetujui atau ditolak)

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • status (optional) - Filter berdasarkan status ("active" atau "rejected")
  • +
  • search (optional) - Pencarian berdasarkan nama penjahit, nama bank, nomor rekening, atau nama pemilik rekening
  • +
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "user_id": 2,
+            "bank_name": "BCA",
+            "account_number": "1234567890",
+            "account_holder_name": "John Doe",
+            "status": "active",
+            "rejection_reason": null,
+            "verified_at": "2024-05-03T10:00:00.000000Z",
+            "created_at": "2024-05-01T10:00:00.000000Z",
+            "updated_at": "2024-05-03T10:00:00.000000Z",
+            "user": {
+                "id": 2,
+  "name": "John Doe",
+  "email": "john@example.com",
+                "role": "penjahit"
+            }
+        },
+        {
+            "id": 2,
+            "user_id": 3,
+            "bank_name": "Mandiri",
+            "account_number": "9876543210",
+            "account_holder_name": "Jane Smith",
+            "status": "rejected",
+            "rejection_reason": "Data tidak sesuai dengan identitas penjahit",
+            "verified_at": "2024-05-02T11:00:00.000000Z",
+            "created_at": "2024-05-01T09:00:00.000000Z", 
+            "updated_at": "2024-05-02T11:00:00.000000Z",
+            "user": {
+                "id": 3,
+                "name": "Jane Smith",
+                "email": "jane@example.com",
+                "role": "penjahit"
+            }
+        }
+    ],
+    "message": "Verified bank accounts retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /admin/bank-accounts/{bankAccount} +

Mendapatkan detail akun bank beserta riwayat penarikannya

+
Headers
+
Authorization: Bearer {token}
+
Path Parameters
+
    +
  • bankAccount - ID akun bank
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "user_id": 2,
+        "bank_name": "BCA",
+        "account_number": "1234567890",
+        "account_holder_name": "John Doe",
+        "status": "active",
+        "rejection_reason": null,
+        "verified_at": "2024-05-03T10:00:00.000000Z",
+        "created_at": "2024-05-02T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:00:00.000000Z",
+        "user": {
+            "id": 2,
+            "name": "John Doe",
+            "email": "john@example.com",
+  "phone_number": "08123456789",
+            "role": "penjahit"
+        },
+        "withdrawals": [
+            {
+                "id": 1,
+                "wallet_id": 1,
+                "bank_account_id": 1,
+                "amount": 500000.00,
+                "status": "completed",
+                "rejection_reason": null,
+                "proof_of_payment": "proof_of_payments/withdrawal_1.jpg",
+                "processed_at": "2024-05-04T14:00:00.000000Z",
+                "created_at": "2024-05-04T10:00:00.000000Z",
+                "updated_at": "2024-05-04T14:00:00.000000Z"
+            }
+        ]
+    },
+    "message": "Bank account detail retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Bank account not found"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /admin/withdrawals/history +

Mendapatkan riwayat penarikan dana yang telah diproses (completed & rejected)

+
Headers
+
Authorization: Bearer {token}
+
Query Parameters
+
    +
  • status (optional) - Filter berdasarkan status penarikan. Nilai yang diperbolehkan: "completed", "rejected"
  • +
  • search (optional) - Pencarian berdasarkan nama pengguna, nomor rekening, atau nama bank
  • +
  • from_date (optional) - Filter dari tanggal tertentu (format: YYYY-MM-DD)
  • +
  • to_date (optional) - Filter sampai tanggal tertentu (format: YYYY-MM-DD)
  • +
  • sort_by (optional) - Kolom yang digunakan untuk pengurutan. Nilai yang diperbolehkan: "created_at", "amount", "processed_at" (default: "processed_at")
  • +
  • sort_order (optional) - Arah pengurutan. Nilai yang diperbolehkan: "asc", "desc" (default: "desc")
  • +
  • per_page (optional) - Jumlah item per halaman (default: 15)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "current_page": 1,
+        "data": [
+            {
+                "id": 1,
+                "wallet_id": 1,
+                "bank_account_id": 1,
+                "amount": 500000.00,
+                "status": "completed",
+                "rejection_reason": null,
+                "proof_of_payment": "proof_of_payments/withdrawal_1.jpg",
+                "processed_at": "2024-05-04T14:00:00.000000Z",
+                "created_at": "2024-05-04T10:00:00.000000Z",
+                "updated_at": "2024-05-04T14:00:00.000000Z",
+                "wallet": {
+                    "id": 1,
+                    "user_id": 2,
+                    "balance": 1500000,
+  "user": {
+                        "id": 2,
+                        "name": "John Doe",
+                        "email": "john@example.com",
+                        "role": "penjahit"
+                    }
+                },
+                "bank_account": {
+    "id": 1,
+                    "bank_name": "BCA",
+                    "account_number": "1234567890",
+                    "account_holder_name": "John Doe"
+                }
+            },
+            {
+                "id": 2,
+                "wallet_id": 1,
+                "bank_account_id": 1,
+                "amount": 300000.00,
+                "status": "rejected",
+                "rejection_reason": "Informasi rekening tidak sesuai dengan identitas penjahit",
+                "proof_of_payment": null,
+                "processed_at": "2024-05-05T15:00:00.000000Z",
+                "created_at": "2024-05-05T11:00:00.000000Z",
+                "updated_at": "2024-05-05T15:00:00.000000Z",
+                "wallet": {
+                    "id": 1,
+                    "user_id": 2,
+                    "balance": 1500000,
+                    "user": {
+                        "id": 2,
+    "name": "John Doe",
+    "email": "john@example.com",
+                        "role": "penjahit"
+                    }
+                },
+                "bank_account": {
+                    "id": 1,
+                    "bank_name": "BCA",
+                    "account_number": "1234567890",
+                    "account_holder_name": "John Doe"
+                }
+            }
+        ],
+        "first_page_url": "http://localhost:8000/api/admin/withdrawals/history?page=1",
+        "from": 1,
+        "last_page": 1,
+        "last_page_url": "http://localhost:8000/api/admin/withdrawals/history?page=1",
+        "links": [
+            {
+                "url": null,
+                "label": "« Previous",
+                "active": false
+            },
+            {
+                "url": "http://localhost:8000/api/admin/withdrawals/history?page=1",
+                "label": "1",
+                "active": true
+            },
+            {
+                "url": null,
+                "label": "Next »",
+                "active": false
+            }
+        ],
+        "next_page_url": null,
+        "path": "http://localhost:8000/api/admin/withdrawals/history",
+        "per_page": 15,
+        "prev_page_url": null,
+        "to": 2,
+        "total": 2
+    },
+    "message": "Withdrawal history retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized"
+    },
+    "message": "Error."
+}
+
+
+
+ +
+

Model Data

+ +

Berikut adalah struktur model data utama yang digunakan dalam API Project Jahit.

+ +

User

+

Representasi pengguna dalam sistem, bisa berupa admin, penjahit, atau pelanggan.

+
{
+    "id": 1,
+    "name": "John Doe",
+    "email": "john@example.com",
+  "role": "penjahit", // atau "pelanggan", "admin"
+    "phone_number": "08123456789",
+    "address": "Jl. Example No. 123",
+  "shop_description": "Jasa jahit profesional dengan pelayanan terbaik", // hanya untuk penjahit
+  "profile_photo": "profile_photos/user1.jpg",
+  "latitude": -6.123456,
+  "longitude": 106.789012,
+  "email_verified_at": "2023-05-01T10:00:00.000000Z",
+    "created_at": "2023-05-01T10:00:00.000000Z",
+    "updated_at": "2023-05-01T10:00:00.000000Z"
+}
+ +

Booking

+

Data pemesanan jasa jahit.

+
{
+  "id": 1,
+  "transaction_code": "TRX-20230501-A1B2C3",
+  "customer_id": 1,
+  "tailor_id": 2,
+  "appointment_date": "2023-05-05",
+  "appointment_time": "10:00",
+  "service_type": "Jahit Baru", // atau "Perbaikan"
+  "category": "Atasan", // atau "Bawahan", "Terusan"
+  "design_photo": "design_photos/design1.jpg",
+  "notes": "Mohon dibuat sesuai ukuran",
+  "status": "reservasi", // atau "dikonfirmasi", "diproses", "selesai", "dibatalkan"
+  "total_price": 150000,
+  "payment_status": "unpaid", // atau "pending", "paid", "expired", "failed", "cancelled"
+  "payment_method": "Midtrans",
+  "midtrans_snap_token": "66e4fa55-fdac-4ef9-91b5-733b97d1b862",
+  "completed_at": null,
+  "created_at": "2023-05-01T10:00:00.000000Z",
+  "updated_at": "2023-05-01T10:00:00.000000Z"
+}
+ +

TailorSpecialization

+

Kategori spesialisasi penjahit.

+
{
+  "id": 1,
+  "name": "Kemeja",
+  "icon": "icons/kemeja.png",
+  "created_at": "2023-05-01T10:00:00.000000Z",
+  "updated_at": "2023-05-01T10:00:00.000000Z"
+}
+ +

TailorService

+

Layanan yang ditawarkan oleh penjahit.

+
{
+  "id": 1,
+  "user_id": 2,
+  "name": "Jahit Kemeja",
+  "description": "Jasa jahit kemeja pria dan wanita",
+  "price": 150000,
+  "is_available": true,
+  "created_at": "2023-05-01T10:00:00.000000Z",
+  "updated_at": "2023-05-01T10:00:00.000000Z"
+}
+ +

TailorGallery

+

Item galeri karya penjahit.

+
{
+  "id": 1,
+  "user_id": 2,
+  "title": "Kemeja Batik",
+  "description": "Kemeja batik pesanan pelanggan",
+  "photo_path": "gallery_photos/kemeja_batik.jpg",
+  "created_at": "2023-05-01T10:00:00.000000Z",
+  "updated_at": "2023-05-01T10:00:00.000000Z"
+}
+ +

TailorRating

+

Penilaian yang diberikan pelanggan untuk penjahit.

+
{
+  "id": 1,
+  "booking_id": 1,
+  "customer_id": 1,
+  "tailor_id": 2,
+  "rating": 5, // 1-5
+  "review": "Sangat puas dengan hasilnya",
+  "created_at": "2023-05-10T10:00:00.000000Z",
+  "updated_at": "2023-05-10T10:00:00.000000Z"
+}
+ +

Wallet

+

Dompet digital penjahit untuk menerima pembayaran.

+
{
+  "id": 1,
+  "user_id": 2,
+  "balance": 1000000.00,
+  "created_at": "2023-05-01T10:00:00.000000Z",
+  "updated_at": "2023-05-10T10:00:00.000000Z"
+}
+ +

BankAccount

+

Akun bank penjahit untuk penarikan dana.

+
{
+  "id": 1,
+  "user_id": 2,
+  "bank_name": "BCA",
+  "account_number": "1234567890",
+  "account_holder_name": "John Doe",
+  "status": "active", // atau "pending", "rejected"
+  "rejection_reason": null,
+  "verified_at": "2023-05-03T10:00:00.000000Z",
+  "created_at": "2023-05-01T10:00:00.000000Z",
+  "updated_at": "2023-05-03T10:00:00.000000Z"
+}
+ +

Withdrawal

+

Permintaan penarikan dana dari wallet ke rekening bank.

+
{
+  "id": 1,
+  "wallet_id": 1,
+  "bank_account_id": 1,
+  "amount": 500000.00,
+  "status": "pending", // atau "processing", "completed", "rejected"
+  "rejection_reason": null,
+  "proof_of_payment": null,
+  "processed_at": null,
+  "created_at": "2023-05-10T10:00:00.000000Z",
+  "updated_at": "2023-05-10T10:00:00.000000Z"
+}
+
+ +
+

Kode Status

+ +

Berikut adalah kode status HTTP yang digunakan dalam API Project Jahit:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KodeStatusDeskripsi
200OKPermintaan berhasil diproses
201CreatedSumber daya baru berhasil dibuat
400Bad RequestFormat permintaan tidak valid
401UnauthorizedKredensial autentikasi tidak valid atau tidak ada
403ForbiddenKlien tidak memiliki hak akses ke sumber daya yang diminta
404Not FoundSumber daya yang diminta tidak ditemukan
422Unprocessable EntityValidasi data gagal
500Internal Server ErrorTerjadi kesalahan pada server
+
+ +
+

Contoh

+ +

Alur Registrasi dan Login Pelanggan

+
    +
  1. Registrasi akun pelanggan: +
    POST /api/pelanggan/register
    +Content-Type: application/json
    +
    +{
    +  "name": "John Doe",
    +  "email": "john@example.com",
    +  "password": "password123",
    +  "password_confirmation": "password123",
    +  "phone_number": "08123456789",
    +    "address": "Jl. Example No. 123",
    +    "latitude": -6.123456,
    +    "longitude": 106.789012
    +}
    +
  2. +
  3. Verifikasi email (jika diperlukan)
  4. +
  5. Login untuk mendapatkan token: +
    POST /api/pelanggan/login
    +Content-Type: application/json
    +
    +{
    +    "email": "john@example.com",
    +    "password": "password123"
    +}
    +
  6. +
  7. Simpan token untuk permintaan berikutnya: +
    Authorization: Bearer 1|laravel_sanctum_token...
    +
  8. +
+ +

Alur Booking Jasa Jahit

+
    +
  1. Cari penjahit berdasarkan spesialisasi: +
    GET /api/tailors/search?specialization=1
    +
  2. +
  3. Lihat detail penjahit: +
    GET /api/tailors/2
    +
  4. +
  5. Buat booking baru: +
    POST /api/tailors/2/book
    +Content-Type: multipart/form-data
    +
    +{
    +    "appointment_date": "2023-05-15",
    +    "appointment_time": "14:00",
    +    "service_type": "Jahit Baru",
    +    "category": "Atasan",
    +    "design_photo": [file],
    +    "notes": "Mohon dibuat sesuai ukuran"
    +}
    +
  6. +
  7. Lakukan pembayaran: +
    POST /api/bookings/5/midtrans/pay
    +
  8. +
  9. Cek status pembayaran secara manual: +
    POST /api/bookings/5/payment-status/check
    +
  10. +
+ +

Alur Penarikan Dana Penjahit

+
    +
  1. Daftarkan rekening bank: +
    POST /api/bank-accounts
    +Content-Type: application/json
    +
    +{
    +    "bank_name": "BCA",
    +    "account_number": "1234567890",
    +    "account_holder_name": "John Doe"
    +}
    +
  2. +
  3. Admin memverifikasi rekening bank: +
    POST /api/admin/bank-accounts/1/verify
    +Content-Type: application/json
    +
    +{
    +    "status": "active"
    +}
    +
  4. +
  5. Penjahit melakukan permintaan penarikan dana: +
    POST /api/withdrawals
    +Content-Type: application/json
    +
    +{
    +    "bank_account_id": 1,
    +    "amount": 500000
    +}
    +
  6. +
  7. Admin memproses permintaan penarikan: +
    POST /api/admin/withdrawals/1/process
    +Content-Type: multipart/form-data
    +
    +{
    +    "status": "processing",
    +    "proof_of_payment": [file]
    +}
    +
  8. +
  9. Admin menyelesaikan proses penarikan: +
    POST /api/admin/withdrawals/1/complete
    +
  10. +
+
+ +
+

File & Media

+ +

Berikut adalah informasi tentang manajemen file dan media dalam API Project Jahit.

+ +

Upload File

+

Untuk mengupload file seperti foto profil, desain pakaian, bukti pembayaran, atau gambar galeri, gunakan format multipart/form-data dalam permintaan API.

+ +
Endpoint yang Mendukung Upload File:
+
    +
  • /profile/photo - Upload foto profil pengguna
  • +
  • /tailors/{tailor}/book - Upload desain pakaian saat membuat booking
  • +
  • /penjahit/gallery - Upload foto untuk galeri penjahit
  • +
  • /admin/withdrawals/{withdrawal}/process - Upload bukti pembayaran penarikan
  • +
+ +
Batasan Upload:
+
    +
  • Format yang didukung: JPG, JPEG, PNG, GIF
  • +
  • Ukuran maksimum: 2MB per file
  • +
  • Resolusi gambar yang direkomendasikan: minimal 300x300 pixel
  • +
+ +

Penyimpanan File

+

File yang diupload akan disimpan di server dengan struktur direktori sebagai berikut:

+
    +
  • profile_photos/ - Foto profil pengguna
  • +
  • design_photos/ - Foto desain pakaian
  • +
  • gallery_photos/ - Foto galeri penjahit
  • +
  • proof_of_payments/ - Bukti pembayaran penarikan
  • +
+ +

Mengakses File

+

File yang telah diupload dapat diakses melalui URL yang dikembalikan dalam respons API. Contoh URL:

+
https://api.project-jahit.com/storage/profile_photos/user1.jpg
+ +

Menghapus File

+

Beberapa endpoint menyediakan operasi untuk menghapus file, seperti:

+
    +
  • DELETE /penjahit/shop-profile/photo - Menghapus foto profil toko
  • +
  • DELETE /penjahit/gallery/{gallery} - Menghapus item galeri
  • +
+
+
+
+
+ + + + + diff --git a/TA_API/resources/views/emails/reset-password.blade.php b/TA_API/resources/views/emails/reset-password.blade.php new file mode 100644 index 0000000..ae8c8cc --- /dev/null +++ b/TA_API/resources/views/emails/reset-password.blade.php @@ -0,0 +1,111 @@ + + + + + + Reset Password + + + +
+
+

TailorHub

+

Reset Password

+
+ +
+

Halo {{ $name }},

+ +

Anda menerima email ini karena kami menerima permintaan reset password untuk akun Anda di TailorHub.

+ +

Berikut adalah PIN reset password Anda:

+ +
+ {{ $pin }} +
+ +

Gunakan PIN ini untuk mereset password Anda. PIN ini akan kadaluarsa dalam {{ $expiresIn }}.

+ +

Jika Anda tidak meminta reset password, Anda dapat mengabaikan email ini dan akun Anda tetap aman.

+ +
+

Jika Anda memiliki pertanyaan, silakan hubungi tim dukungan kami.

+
+ +

Demi keamanan, jangan bagikan PIN ini kepada siapapun.

+
+ + +
+ + \ No newline at end of file diff --git a/TA_API/resources/views/emails/verification-error.blade.php b/TA_API/resources/views/emails/verification-error.blade.php new file mode 100644 index 0000000..3cccaec --- /dev/null +++ b/TA_API/resources/views/emails/verification-error.blade.php @@ -0,0 +1,140 @@ + + + + + + Verifikasi Email Gagal - TailorHub + + + + +
+
+

TailorHub

+
+ +
+
+ + + + +
+ +

Verifikasi Email Gagal

+ +
+ {{ $message }} +
+ +
+

Kemungkinan penyebab:

+
    +
  • Link verifikasi sudah kadaluarsa (berlaku 60 menit)
  • +
  • Link verifikasi sudah digunakan sebelumnya
  • +
  • Link verifikasi tidak valid atau telah diubah
  • +
+
+ +

Silakan coba kirim ulang email verifikasi atau hubungi tim dukungan kami jika Anda terus mengalami masalah.

+ + +
+ + +
+ + \ No newline at end of file diff --git a/TA_API/resources/views/emails/verification-success.blade.php b/TA_API/resources/views/emails/verification-success.blade.php new file mode 100644 index 0000000..e92d173 --- /dev/null +++ b/TA_API/resources/views/emails/verification-success.blade.php @@ -0,0 +1,122 @@ + + + + + + Verifikasi Email Berhasil - TailorHub + + + + +
+
+

TailorHub

+
+ +
+
+ + + + +
+ +

Verifikasi Email Berhasil!

+ +
+ {{ $message }} +
+ + + +

Sekarang Anda dapat menggunakan semua fitur TailorHub.

+

Silakan tutup halaman ini dan kembali ke aplikasi.

+
+ + +
+ + \ No newline at end of file diff --git a/TA_API/resources/views/emails/verify-email.blade.php b/TA_API/resources/views/emails/verify-email.blade.php new file mode 100644 index 0000000..f184180 --- /dev/null +++ b/TA_API/resources/views/emails/verify-email.blade.php @@ -0,0 +1,108 @@ + + + + + + Verifikasi Email + + + +
+
+

TailorHub

+

Verifikasi Email Anda

+
+ +
+

Halo {{ $name }},

+ +

Terima kasih telah mendaftar di TailorHub. Untuk melanjutkan, silakan verifikasi alamat email Anda dengan mengklik tombol di bawah ini:

+ + + +

Jika tombol di atas tidak berfungsi, Anda juga dapat menyalin dan menempelkan URL berikut ke browser Anda:

+ +
+ {{ $url }} +
+ +

Jika Anda tidak merasa mendaftar di TailorHub, Anda dapat mengabaikan email ini.

+ +

Link verifikasi ini akan kadaluarsa dalam {{ $expiresIn }}.

+
+ + +
+ + \ No newline at end of file diff --git a/TA_API/resources/views/wallet-endpoints.blade.php b/TA_API/resources/views/wallet-endpoints.blade.php new file mode 100644 index 0000000..966d657 --- /dev/null +++ b/TA_API/resources/views/wallet-endpoints.blade.php @@ -0,0 +1,438 @@ +
+

Wallet & Withdrawal

+ +
+ GET + /wallet +

Mendapatkan informasi wallet pengguna

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": {
+        "balance": 1000000.00,
+        "transactions": [
+            {
+                "id": 1,
+                "type": "credit",
+                "amount": 500000.00,
+                "description": "Pembayaran booking #TRX-001",
+                "status": "success",
+                "created_at": "2024-05-03T10:00:00.000000Z",
+                "booking": {
+                    "id": 1,
+                    "transaction_code": "TRX-001",
+                    "service_type": "jahit",
+                    "category": "baju"
+                }
+            }
+        ]
+    },
+    "message": "Wallet information retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized access"
+    },
+    "message": "Error."
+}
+
+ +
+ GET + /bank-accounts +

Mendapatkan daftar akun bank pengguna

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "bank_name": "BCA",
+            "account_number": "1234567890",
+            "account_holder_name": "John Doe",
+            "status": "active",
+            "verified_at": "2024-05-03T10:00:00.000000Z",
+            "created_at": "2024-05-03T10:00:00.000000Z",
+            "updated_at": "2024-05-03T10:00:00.000000Z"
+        },
+        {
+            "id": 2,
+            "bank_name": "Mandiri",
+            "account_number": "0987654321",
+            "account_holder_name": "John Doe",
+            "status": "pending",
+            "verified_at": null,
+            "created_at": "2024-05-03T11:00:00.000000Z",
+            "updated_at": "2024-05-03T11:00:00.000000Z"
+        }
+    ],
+    "message": "Bank accounts retrieved successfully"
+}
+
Status Akun Bank
+
    +
  • pending - Akun bank sedang menunggu verifikasi admin
  • +
  • active - Akun bank sudah diverifikasi dan dapat digunakan
  • +
  • rejected - Akun bank ditolak oleh admin
  • +
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized access"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /bank-accounts +

Mendaftarkan akun bank baru

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "bank_name": "BCA",
+    "account_number": "1234567890",
+    "account_holder_name": "John Doe"
+}
+
Validasi
+
    +
  • bank_name - Wajib diisi, nama bank
  • +
  • account_number - Wajib diisi, nomor rekening
  • +
  • account_holder_name - Wajib diisi, nama pemilik rekening
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "bank_name": "BCA",
+        "account_number": "1234567890",
+        "account_holder_name": "John Doe",
+        "status": "pending",
+        "created_at": "2024-05-03T10:00:00.000000Z"
+    },
+    "message": "Bank account registered successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "bank_name": ["The bank name field is required."],
+        "account_number": ["The account number field is required."],
+        "account_holder_name": ["The account holder name field is required."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /withdrawals +

Meminta penarikan dana

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Request Body
+
{
+    "bank_account_id": 1,
+    "amount": 500000
+}
+
Validasi
+
    +
  • bank_account_id - Wajib diisi, ID dari akun bank yang akan digunakan
  • +
  • amount - Wajib diisi, jumlah dana yang akan ditarik (minimal 10000)
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "wallet_id": 1,
+        "bank_account_id": 1,
+        "amount": 500000.00,
+        "status": "pending",
+        "created_at": "2024-05-03T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:00:00.000000Z"
+    },
+    "message": "Withdrawal request submitted successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Insufficient balance."
+    },
+    "message": "Insufficient balance."
+}
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid bank account."
+    },
+    "message": "Invalid bank account."
+}
+
+ +
+ GET + /withdrawals +

Mendapatkan riwayat penarikan dana

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "wallet_id": 1,
+            "bank_account_id": 1,
+            "amount": 500000.00,
+            "status": "completed",
+            "rejection_reason": null,
+            "proof_of_payment": "proof_1.jpg",
+            "processed_at": "2024-05-03T11:00:00.000000Z",
+            "created_at": "2024-05-03T10:00:00.000000Z",
+            "updated_at": "2024-05-03T11:00:00.000000Z",
+            "bank_account": {
+                "id": 1,
+                "bank_name": "BCA",
+                "account_number": "1234567890",
+                "account_holder_name": "John Doe",
+                "status": "active"
+            }
+        },
+        {
+            "id": 2,
+            "wallet_id": 1,
+            "bank_account_id": 1,
+            "amount": 300000.00,
+            "status": "pending",
+            "rejection_reason": null,
+            "proof_of_payment": null,
+            "processed_at": null,
+            "created_at": "2024-05-04T10:00:00.000000Z",
+            "updated_at": "2024-05-04T10:00:00.000000Z",
+            "bank_account": {
+                "id": 1,
+                "bank_name": "BCA",
+                "account_number": "1234567890",
+                "account_holder_name": "John Doe",
+                "status": "active"
+            }
+        }
+    ],
+    "message": "Withdrawal history retrieved successfully"
+}
+
Status Penarikan
+
    +
  • pending - Permintaan penarikan menunggu diproses oleh admin
  • +
  • processing - Permintaan penarikan sedang diproses
  • +
  • completed - Permintaan penarikan telah selesai
  • +
  • rejected - Permintaan penarikan ditolak
  • +
+
+ +

Admin Endpoints

+ +
+ GET + /admin/withdrawals/pending +

Mendapatkan daftar permintaan penarikan yang pending

+
Headers
+
Authorization: Bearer {token}
+
Response
+
{
+    "success": true,
+    "data": [
+        {
+            "id": 1,
+            "wallet_id": 1,
+            "bank_account_id": 1,
+            "amount": 500000.00,
+            "status": "pending",
+            "rejection_reason": null,
+            "proof_of_payment": null,
+            "processed_at": null,
+            "created_at": "2024-05-03T10:00:00.000000Z",
+            "updated_at": "2024-05-03T10:00:00.000000Z",
+            "wallet": {
+                "id": 1,
+                "user_id": 2,
+                "balance": 1000000.00,
+                "user": {
+                    "id": 2,
+                    "name": "John Doe",
+                    "email": "john@example.com",
+                    "role": "penjahit"
+                }
+            },
+            "bank_account": {
+                "id": 1,
+                "bank_name": "BCA",
+                "account_number": "1234567890",
+                "account_holder_name": "John Doe",
+                "status": "active"
+            }
+        }
+    ],
+    "message": "Pending withdrawals retrieved successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Unauthorized access"
+    },
+    "message": "Error."
+}
+
+ +
+ POST + /admin/withdrawals/{withdrawal}/process +

Memproses permintaan penarikan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: multipart/form-data
+
Path Parameters
+
    +
  • withdrawal - ID permintaan penarikan
  • +
+
Request Body
+
{
+    "status": "processing", // atau "rejected"
+    "rejection_reason": "", // wajib diisi jika status = "rejected"
+    "proof_of_payment": [file] // wajib diupload jika status = "processing"
+}
+
Validasi
+
    +
  • status - Wajib diisi, nilai yang valid: "processing" atau "rejected"
  • +
  • rejection_reason - Wajib diisi jika status = "rejected"
  • +
  • proof_of_payment - Wajib diisi jika status = "processing", file bukti pembayaran
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "wallet_id": 1,
+        "bank_account_id": 1,
+        "amount": 500000.00,
+        "status": "processing",
+        "rejection_reason": null,
+        "proof_of_payment": "proofs/withdrawal_1_proof.jpg",
+        "processed_at": "2024-05-03T10:30:00.000000Z",
+        "created_at": "2024-05-03T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:30:00.000000Z"
+    },
+    "message": "Withdrawal processed successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "status": ["The status field is required."],
+        "rejection_reason": ["The rejection reason field is required when status is rejected."],
+        "proof_of_payment": ["The proof of payment field is required when status is processing."]
+    },
+    "message": "Validation Error."
+}
+
+ +
+ POST + /admin/withdrawals/{withdrawal}/complete +

Menyelesaikan proses penarikan

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • withdrawal - ID permintaan penarikan
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "wallet_id": 1,
+        "bank_account_id": 1,
+        "amount": 500000.00,
+        "status": "completed",
+        "rejection_reason": null,
+        "proof_of_payment": "proofs/withdrawal_1_proof.jpg",
+        "processed_at": "2024-05-03T10:30:00.000000Z",
+        "created_at": "2024-05-03T10:00:00.000000Z",
+        "updated_at": "2024-05-03T11:00:00.000000Z"
+    },
+    "message": "Withdrawal completed successfully"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "error": "Invalid status."
+    },
+    "message": "Invalid status."
+}
+
+ +
+ POST + /admin/bank-accounts/{bankAccount}/verify +

Memverifikasi akun bank

+
Headers
+
Authorization: Bearer {token}
+Content-Type: application/json
+
Path Parameters
+
    +
  • bankAccount - ID akun bank
  • +
+
Request Body
+
{
+    "status": "active", // atau "rejected"
+    "rejection_reason": null // wajib diisi jika status = "rejected"
+}
+
Validasi
+
    +
  • status - Wajib diisi, nilai yang valid: "active" atau "rejected"
  • +
  • rejection_reason - Wajib diisi jika status = "rejected"
  • +
+
Response
+
{
+    "success": true,
+    "data": {
+        "id": 1,
+        "user_id": 2,
+        "bank_name": "BCA",
+        "account_number": "1234567890",
+        "account_holder_name": "John Doe",
+        "status": "active",
+        "rejection_reason": null,
+        "verified_at": "2024-05-03T10:00:00.000000Z",
+        "created_at": "2024-05-02T10:00:00.000000Z",
+        "updated_at": "2024-05-03T10:00:00.000000Z"
+    },
+    "message": "Bank account verification completed"
+}
+
Error Response
+
{
+    "success": false,
+    "data": {
+        "status": ["The status field must be one of: active, rejected."],
+        "rejection_reason": ["The rejection reason field is required when status is rejected."]
+    },
+    "message": "Validation Error."
+}
+
+
\ No newline at end of file diff --git a/TA_API/resources/views/welcome.blade.php b/TA_API/resources/views/welcome.blade.php new file mode 100644 index 0000000..c893b80 --- /dev/null +++ b/TA_API/resources/views/welcome.blade.php @@ -0,0 +1,277 @@ + + + + + + + Laravel + + + + + + + @if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot'))) + @vite(['resources/css/app.css', 'resources/js/app.js']) + @else + + @endif + + +
+ @if (Route::has('login')) + + @endif +
+
+
+
+

Let's get started

+

Laravel has an incredibly rich ecosystem.
We suggest starting with the following.

+ + +
+
+ {{-- Laravel Logo --}} + + + + + + + + + + + {{-- Light Mode 12 SVG --}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{-- Dark Mode 12 SVG --}} + +
+
+
+
+ + @if (Route::has('login')) + + @endif + + diff --git a/TA_API/routes/api.php b/TA_API/routes/api.php new file mode 100644 index 0000000..073218d --- /dev/null +++ b/TA_API/routes/api.php @@ -0,0 +1,241 @@ +group(function () { + // Test route + Route::get('/test', function () { + return response()->json([ + 'message' => 'API is working' + ]); + }); + + // Email verification routes + Route::get('/email/verify/{id}/{hash}', [EmailVerificationController::class, 'verify']) + ->middleware('signed') + ->name('verification.verify'); + + // Get all specializations (public) + Route::get('/specializations', [AuthController::class, 'getSpecializations']); + Route::get('/specializations/all', [TailorSpecializationController::class, 'getAllSpecializations']); + + // Search tailors + Route::get('/tailors/search', [TailorSearchController::class, 'searchBySpecialization']); + Route::get('/tailors/search/name/{name}', [TailorSearchController::class, 'searchByName']); + + // Protected routes + Route::middleware('auth:sanctum')->group(function () { + // Other email verification routes + Route::post('/email/verification-notification', [EmailVerificationController::class, 'sendVerificationEmail']); + Route::post('/email/verification-resend', [EmailVerificationController::class, 'resend']); + + Route::post('/logout', [AuthController::class, 'logout']); + Route::get('/profile', [AuthController::class, 'profile']); + Route::post('/profile', [AuthController::class, 'updateProfile']); + + // Get recommended tailors for customer + Route::get('/tailors/recommended', [TailorSearchController::class, 'getRecommended']); + + // Booking routes for customers + Route::middleware(['can:pelanggan'])->prefix('bookings')->group(function () { + Route::post('/', [BookingController::class, 'store']); + Route::get('/customer', [BookingController::class, 'customerBookings']); + Route::get('/customer/status/{status}', [BookingController::class, 'customerBookingsByStatus']); + Route::get('/{booking}', [BookingController::class, 'show']); + Route::post('/{booking}/cancel', [BookingController::class, 'cancelBooking']); + }); + + // Direct booking from tailor detail + Route::post('/tailors/{tailor}/book', [BookingController::class, 'bookTailor'])->middleware('can:pelanggan'); + + // Booking routes for tailors + Route::middleware(['can:penjahit'])->prefix('bookings')->group(function () { + Route::post('/{booking}/accept', [BookingController::class, 'acceptBooking']); + Route::post('/{booking}/reject', [BookingController::class, 'rejectBooking']); + Route::patch('/{booking}/status', [BookingController::class, 'updateStatus']); + Route::post('/{booking}/measurements', [BookingController::class, 'updateMeasurements']); + Route::post('/{booking}/repair', [BookingController::class, 'updateRepairDetails']); + Route::post('/{booking}/complete', [BookingController::class, 'completeBooking']); + Route::patch('/{booking}/price', [BookingController::class, 'updatePrice']); + Route::post('/{booking}/payment', [BookingController::class, 'updatePaymentStatus']); + Route::post('/{booking}/completion-payment', [BookingController::class, 'processCompletionPayment']); + Route::get('/{booking}', [BookingController::class, 'show']); + }); + + // Penjahit protected routes + Route::middleware(['can:penjahit'])->prefix('penjahit')->group(function () { + Route::get('/dashboard', [TailorDashboardController::class, 'index']); + Route::post('/specializations', [AuthController::class, 'updateSpecializations']); + + // Calendar routes + Route::get('/calendar/{month}/{year}', [TailorCalendarController::class, 'getCalendarBookings']); + Route::get('/calendar/date/{date}', [TailorCalendarController::class, 'getDateBookings']); + + // Shop profile routes + Route::get('/shop-profile', [TailorProfileController::class, 'getProfile']); + Route::post('/shop-profile', [TailorProfileController::class, 'updateProfile']); + Route::delete('/shop-profile/photo', [TailorProfileController::class, 'deleteProfilePhoto']); + + // Gallery routes + Route::get('/gallery', [TailorGalleryController::class, 'index']); + Route::post('/gallery', [TailorGalleryController::class, 'store']); + Route::put('/gallery/{gallery}', [TailorGalleryController::class, 'update']); + Route::delete('/gallery/{gallery}', [TailorGalleryController::class, 'destroy']); + + // Services routes + Route::get('/services', [TailorServiceController::class, 'index']); + Route::post('/services', [TailorServiceController::class, 'store']); + Route::put('/services/{service}', [TailorServiceController::class, 'update']); + Route::delete('/services/{service}', [TailorServiceController::class, 'destroy']); + Route::patch('/services/{service}/toggle', [TailorServiceController::class, 'toggleAvailability']); + + // Booking routes for tailors + Route::get('/bookings', [BookingController::class, 'tailorBookings']); + Route::get('/bookings/status/{status}', [BookingController::class, 'tailorBookingsByStatus']); + }); + + // Public routes for viewing tailor services and gallery + Route::get('/tailors/{tailor}/services', [TailorServiceController::class, 'getTailorServices']); + Route::get('/tailors/{tailor}/gallery', [TailorGalleryController::class, 'getTailorGallery']); + + // Rating routes + Route::post('bookings/{booking}/rate', [RatingController::class, 'store']); + Route::put('ratings/{rating}', [RatingController::class, 'update']); + + // Upload foto profil + Route::post('/profile/photo', [AuthController::class, 'uploadProfilePhoto']); + + // Get completed booking details + Route::get('bookings/{booking}/completed-details', [BookingController::class, 'getCompletedBookingDetails']); + + // Accept booking and change status to diproses + Route::post('bookings/{booking}/accept', [BookingController::class, 'acceptBooking']); + + // Complete booking + Route::post('bookings/{booking}/complete', [BookingController::class, 'completeBooking']); + + // Midtrans Payment routes + Route::post('/bookings/{booking}/midtrans/pay', [MidtransController::class, 'initiatePayment']); + Route::get('/bookings/{booking}/payment-status', [MidtransController::class, 'checkPaymentStatus']); + Route::post('/bookings/{booking}/payment-status/check', [MidtransController::class, 'manualCheckStatus']); + + // Wallet routes + Route::get('/wallet', [WalletController::class, 'getWallet']); + Route::get('/bank-accounts', [WalletController::class, 'getBankAccounts']); + Route::post('/bank-accounts', [WalletController::class, 'registerBankAccount']); + Route::post('/withdrawals', [WalletController::class, 'requestWithdrawal']); + Route::get('/withdrawals', [WalletController::class, 'getWithdrawalHistory']); + }); + + // Get tailor detail + Route::get('/tailors/{id}', [TailorSearchController::class, 'getTailorDetail'])->where('id', '[0-9]+'); + + // Pelanggan routes + Route::prefix('pelanggan')->group(function () { + Route::post('/register', [AuthController::class, 'registerPelanggan']); + Route::post('/login', [AuthController::class, 'loginPelanggan']); + Route::post('/forgot-password', [ForgotPasswordController::class, 'sendResetLinkEmail']); + Route::post('/reset-password', [ForgotPasswordController::class, 'reset']); + }); + + // Penjahit routes + Route::prefix('penjahit')->group(function () { + Route::post('/register', [AuthController::class, 'registerPenjahit']); + Route::post('/login', [AuthController::class, 'loginPenjahit']); + Route::post('/forgot-password', [ForgotPasswordController::class, 'sendResetLinkEmail']); + Route::post('/reset-password', [ForgotPasswordController::class, 'reset']); + }); + + Route::get('tailors/{tailor}/ratings', [RatingController::class, 'getTailorRatings']); + + // Customer dashboard + Route::get('/dashboard', [TailorSearchController::class, 'getDashboardData'])->middleware('auth:sanctum', 'role:pelanggan'); + + // Admin routes + Route::post('/admin/login', [AuthController::class, 'loginAdmin']); + + // Admin protected routes + Route::middleware(['auth:sanctum', 'can:admin'])->group(function () { + Route::get('/admin/dashboard', [AdminDashboardController::class, 'index']); + + // Admin profile routes + Route::get('/admin/profile', [AuthController::class, 'profile']); + Route::post('/admin/profile', [AuthController::class, 'updateProfile']); + Route::post('/admin/profile/photo', [AuthController::class, 'uploadProfilePhoto']); + + // Customer management routes + Route::get('/customers', [CustomerController::class, 'getAllCustomers']); + Route::get('/customers/{id}', [CustomerController::class, 'getCustomerDetail']); + Route::get('/customers/{id}/transactions', [CustomerController::class, 'getCustomerTransactions']); + Route::put('/customers/{id}/specializations', [CustomerController::class, 'updateCustomerSpecializations']); + Route::delete('/customers/{id}', [CustomerController::class, 'deleteCustomer']); + + // Specialization management routes + Route::get('/specializations', [TailorSpecializationController::class, 'index']); + Route::post('/specializations', [TailorSpecializationController::class, 'store']); + Route::get('/specializations/{id}', [TailorSpecializationController::class, 'show']); + Route::put('/specializations/{id}', [TailorSpecializationController::class, 'update']); + Route::delete('/specializations/{id}', [TailorSpecializationController::class, 'destroy']); + Route::post('specializations/{id}/update', [TailorSpecializationController::class, 'update']); + + // Booking management routes + Route::get('/bookings', [BookingController::class, 'getAllBookings']); + + // Admin withdrawal routes + Route::get('/admin/withdrawals/pending', [AdminWithdrawalController::class, 'getPendingWithdrawals']); + Route::get('/admin/bank-accounts/pending', [AdminWithdrawalController::class, 'getPendingBankAccounts']); + Route::post('/admin/withdrawals/{withdrawal}/process', [AdminWithdrawalController::class, 'processWithdrawal']); + Route::post('/admin/bank-accounts/{bankAccount}/verify', [AdminWithdrawalController::class, 'verifyBankAccount']); + Route::get('/admin/bank-accounts/verified', [AdminWithdrawalController::class, 'getVerifiedBankAccounts']); + Route::get('/admin/bank-accounts/{bankAccount}', [AdminWithdrawalController::class, 'getBankAccountDetail']); + Route::get('/admin/withdrawals/history', [AdminWithdrawalController::class, 'getWithdrawalHistory']); + }); + + // Get all tailors with complete data + Route::get('/tailors', [TailorController::class, 'getAllTailors']); + + // Get all tailors without rating filter (for admin only) + Route::middleware(['auth:sanctum', 'can:admin'])->group(function () { + Route::get('/tailors/all', [TailorController::class, 'getAllTailorsNoFilter']); + Route::delete('/tailors/{id}', [TailorController::class, 'deleteTailor']); + Route::put('/tailors/{id}', [TailorController::class, 'updateTailor']); + }); + + // Midtrans notification callback - no auth required + Route::post('/midtrans/notification', [MidtransController::class, 'notificationHandler']); + + // Documentation routes + Route::get('/doc', [DocumentationController::class, 'index']); + Route::get('/doc/{section}', [DocumentationController::class, 'show']); +}); \ No newline at end of file diff --git a/TA_API/routes/console.php b/TA_API/routes/console.php new file mode 100644 index 0000000..3c9adf1 --- /dev/null +++ b/TA_API/routes/console.php @@ -0,0 +1,8 @@ +comment(Inspiring::quote()); +})->purpose('Display an inspiring quote'); diff --git a/TA_API/routes/web.php b/TA_API/routes/web.php new file mode 100644 index 0000000..f941236 --- /dev/null +++ b/TA_API/routes/web.php @@ -0,0 +1,43 @@ +json([ + 'name' => 'Project Jahit API', + 'version' => '1.0.0', + 'description' => 'API untuk aplikasi Project Jahit', + 'documentation' => url('/docs') + ]); +}); + +// Route untuk akses file dari storage +Route::get('/storage/{path}', [FileAccessController::class, 'serveFile']) + ->where('path', '.*') + ->name('storage.file'); + +// Route khusus untuk file di folder tertentu +Route::get('/storage/{directory}/{filename}', [FileAccessController::class, 'serveDirectoryFile']) + ->name('storage.directory.file'); + +// Route untuk dokumentasi API +Route::get('/docs', function () { + return view('api-docs'); +}); + +Route::get('/docs/{section}', function ($section) { + return view('api-docs', ['section' => $section]); +}); diff --git a/TA_API/storage/app/.gitignore b/TA_API/storage/app/.gitignore new file mode 100644 index 0000000..fedb287 --- /dev/null +++ b/TA_API/storage/app/.gitignore @@ -0,0 +1,4 @@ +* +!private/ +!public/ +!.gitignore diff --git a/TA_API/storage/app/private/.gitignore b/TA_API/storage/app/private/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/storage/app/private/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/storage/app/public/.gitignore b/TA_API/storage/app/public/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/storage/framework/.gitignore b/TA_API/storage/framework/.gitignore new file mode 100644 index 0000000..05c4471 --- /dev/null +++ b/TA_API/storage/framework/.gitignore @@ -0,0 +1,9 @@ +compiled.php +config.php +down +events.scanned.php +maintenance.php +routes.php +routes.scanned.php +schedule-* +services.json diff --git a/TA_API/storage/framework/cache/.gitignore b/TA_API/storage/framework/cache/.gitignore new file mode 100644 index 0000000..01e4a6c --- /dev/null +++ b/TA_API/storage/framework/cache/.gitignore @@ -0,0 +1,3 @@ +* +!data/ +!.gitignore diff --git a/TA_API/storage/framework/cache/data/.gitignore b/TA_API/storage/framework/cache/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/storage/framework/cache/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/storage/framework/sessions/.gitignore b/TA_API/storage/framework/sessions/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/storage/framework/testing/.gitignore b/TA_API/storage/framework/testing/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/storage/framework/testing/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/storage/framework/views/.gitignore b/TA_API/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/storage/logs/.gitignore b/TA_API/storage/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_API/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_API/test-access.php b/TA_API/test-access.php new file mode 100644 index 0000000..7e7ec60 --- /dev/null +++ b/TA_API/test-access.php @@ -0,0 +1,25 @@ + + + + + Test Akses File + + + +

Test Akses File di storage/public

+ +
+

File di design_photos

+ Test Image 1 + Test Image 2 + Test Image 3 +
+ + \ No newline at end of file diff --git a/TA_API/tests/Feature/ExampleTest.php b/TA_API/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..8364a84 --- /dev/null +++ b/TA_API/tests/Feature/ExampleTest.php @@ -0,0 +1,19 @@ +get('/'); + + $response->assertStatus(200); + } +} diff --git a/TA_API/tests/TestCase.php b/TA_API/tests/TestCase.php new file mode 100644 index 0000000..fe1ffc2 --- /dev/null +++ b/TA_API/tests/TestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } +} diff --git a/TA_API/vite.config.js b/TA_API/vite.config.js new file mode 100644 index 0000000..29fbfe9 --- /dev/null +++ b/TA_API/vite.config.js @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [ + laravel({ + input: ['resources/css/app.css', 'resources/js/app.js'], + refresh: true, + }), + tailwindcss(), + ], +}); diff --git a/TA_android/.env b/TA_android/.env new file mode 100644 index 0000000..612c526 --- /dev/null +++ b/TA_android/.env @@ -0,0 +1,12 @@ +# API_BASE_URL=https://api.tailorhub.my.id/api +# API_IMAGE_BASE_URL=https://api.tailorhub.my.id + +API_BASE_URL=https://api-tailorhub.stuffly.my.id/api +API_IMAGE_BASE_URL=https://api-tailorhub.stuffly.my.id + +# API_BASE_URL=http://127.0.0.1:8000/api +# API_IMAGE_BASE_URL=http://127.0.0.1:8000 + + +# API_BASE_URL=http://10.0.2.2:8000/api +# API_IMAGE_BASE_URL=http://10.0.2.2:8000 diff --git a/TA_android/.gitignore b/TA_android/.gitignore new file mode 100644 index 0000000..29a3a50 --- /dev/null +++ b/TA_android/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/TA_android/.metadata b/TA_android/.metadata new file mode 100644 index 0000000..878648b --- /dev/null +++ b/TA_android/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "ea121f8859e4b13e47a8f845e4586164519588bc" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + - platform: android + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/TA_android/.vscode/settings.json b/TA_android/.vscode/settings.json new file mode 100644 index 0000000..d9d37f2 --- /dev/null +++ b/TA_android/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "workbench.colorCustomizations": { + "minimap.background": "#00000000", + "scrollbar.shadow": "#00000000" + } +} \ No newline at end of file diff --git a/TA_android/README.md b/TA_android/README.md new file mode 100644 index 0000000..e0e29e7 --- /dev/null +++ b/TA_android/README.md @@ -0,0 +1,16 @@ +# tailorhub + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/TA_android/analysis_options.yaml b/TA_android/analysis_options.yaml new file mode 100644 index 0000000..b33e6b1 --- /dev/null +++ b/TA_android/analysis_options.yaml @@ -0,0 +1,36 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +analyzer: + errors: + unused_local_variable: ignore + dead_code: ignore + unused_import: ignore + missing_return: ignore + prefer_const_constructors: ignore + non_constant_identifier_names: ignore + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/TA_android/android/.gitignore b/TA_android/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/TA_android/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/TA_android/android/app/build.gradle.kts b/TA_android/android/app/build.gradle.kts new file mode 100644 index 0000000..cc7d714 --- /dev/null +++ b/TA_android/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.tailorhub" + compileSdk = flutter.compileSdkVersion + ndkVersion = "29.0.13113456" + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.tailorhub" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/TA_android/android/app/src/debug/AndroidManifest.xml b/TA_android/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/TA_android/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/TA_android/android/app/src/main/AndroidManifest.xml b/TA_android/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8fb6d20 --- /dev/null +++ b/TA_android/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TA_android/android/app/src/main/kotlin/com/example/tailorhub/MainActivity.kt b/TA_android/android/app/src/main/kotlin/com/example/tailorhub/MainActivity.kt new file mode 100644 index 0000000..cb6220e --- /dev/null +++ b/TA_android/android/app/src/main/kotlin/com/example/tailorhub/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.tailorhub + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/TA_android/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/TA_android/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..8072d05239dc976bbe320c0aa58bb1eb77aa6456 GIT binary patch literal 3577 zcmd5<`8$-4*M3lvY(qtMPh*KPvWE~4X6*YCp>IPX^_gT}8Wo;FmN6Qm!N+8mElSx# z*(Q=Ld#J`fp_+ue-oN1e<^AFN!#U@=&V60yoL|m;UpK+l+KiW5lp6p5UJM$tKd7|- z4KB`u+`f5I?4aLj3G*LaS$+wdaBHv~i6tqMdqSQbG@8j7v$44s-vTkO&F^ydNS0KNefwBrN# zjxmeh;+p<_v|(@I3(>#cac6Jq0zL;qyDr5G4u=pdcKlVKS{PhE3dqgd##2%`@M;}9 zNdgjZJBdVUxh+QNZ44=7$sHp>d_Y;C@C={k?#UjSYi`0a;|c0mljpZgvPFUo*_ zN?9?7Z+462x?XDMuiNB2BII_`4hFn+5Ydvr-){O*wbny`MMq3};C($!1dbiFK7_{r z-}9v>Q}Q1+fdx?k#;>&6ak>cu_m1Fupu0!Zq$KU>du5&1FZN$JYS16K@3GSw-=7hT zNJ10-h(IJ4wK@6Wag^+}9)A5kdabeNKmLUrL9aa^Xh(XU7x>N&(0|Odj$0OR3dzm4 z$+*Sdm~%P-O<8i=$!JKNkQ|ev4cf`Y>%5amC6tI^c@$rvblZq#!VU8^}-f@U^H&+ZLZ3Kkx%WH4Sh7En-Dd# zp8sWvX(kWmcG0~6{49BGVv%LoY3aCxHG&va>>m~z-sORw{eC@((i-t|#3e{S&qnMb zxxo6hhxH-1*^qP1;YLRiB4)q3=YKy>q@a*A3&P@(K;F5I^X@`}WHxVe%qyj1aqa0i zaf9ipX?{Lcng5{Q7tGvBAO?b6q<^yFlta>|0) z!8QWyx<-AwiZ6hf=B#QY<|7jGSkSK7LXV2 zYN)c04}5n%_=8o2@b4tWVz-QumkdkTHC8KY`-O9^t-Uso>DF3TKxuDO;e%aj13 zH0y@NKlJ{-A#VXzDu?ff2^5bseS)&c9bSZi)AU^~@NfRx4SO432>Z=lz)nZ2=`B52 z&DUx(k2B@e95usJCyxyXC!zQ!T?7V`pu5?mT#J-@#a1{c6JIEKA+fH4U1NzwRY;tS>`7ZAXPrXi1bu9ws&2J^UwBDUnfkX>+5OpQ8vt&AqhRA3kDX>NQ%EnU#|0Tl^X!lmeB`N08QaEjt zjUFWiN(wKFnsLr`k&+3LKd`2qD)<|`U_bYX0r|S+&N!pFe}LZ}2KVX57VJEYIxigT z)7UD}Fpgvi$4F&9Fy2;Rxf|H>nTxVetK*5HE&@k~Qk|x-!qTCp#UQ{jaYCta{Bg-wPI6 z&@2(z1i|@y=&nrl4M&2g1hzZLkB9I7P?ZTqTF@<{<|2)y>0E4iAi8C1ac>F9gR_x1ZSKiCgWnk~yxJ}*;kE?#Z{3gqMhZ?ldX9}7hnb&G&1$sTMr~u=0 z&qR`LPMlA6c6Xdg8(`cfxx5HcspYBBBT@KE>#cKwtmCof@ zx^!L8r+ThStdGt>j~V*Lz!Wc8(Cwo4Y-MF-Ut?qA?TVAmoccfa)I50rt%OK2?%V=m z@GVZS%3M4lE=4pof@xD#eNPvRP@L+>IZ=6LYnT3WCeKS|^*H#)I`8v!N3KvSSJu}V z0T;^s+dSZ3>6C>8vF*z2!V1vT?ymn5L*43jhFB795ssmL^GiR42t^aW#6^&KE|Seg zwS8T+i{>J)f7=2KBhXTUT{T?QF%b>wR{T``=szBesb~#35ArLXR2rJIUsyPqDxdK} zml0C(_)dc7r;%@O&de~rEAE($9d!@PD~LytJA>5`)2Xlv&^F`LUUz6DywfOOT5Y2h z9BM`kYU!LWcy6oE{W~oqYx_6tp$SbP;^tg?Ts>kim>%VLdZi8>V(4sU(zy+X6|h?T z{U>gG$%Bwk=Za6}S>~SFTEk<1gb$Sy5f18<*>nr-Y^so*dME3WJe1`hOrm(zdT;&U zddTaRq}15ZaI)`nsdkFk^4HU~@t9ULL>=Bl*XIV$y|DAF%Pcu@9!r%q2v$}@rJIO% z7;Y(XD)JE}(lF|T#V`IDnmw*qFoF{yi~5uXLqASXjwiyGRn4yHrm;KB8qChX3fuI& zFs87Uz_S~}i3$$CRktLfPpt=U%62zt0RKD>TEEQPGki3bCBEtZQ>V1WHIOZ@4OX`* zPSDGt^X-@b+M|*CH*>Zm2g&>u$d!|U9>4xGpl-#8o8UX+q2Ehy4H$YcV_XPdbqYmn zEY55CwumEAO*)@8vFdqj9UmujeS938GFgTluQP|}dYaF=^fD;LUAQPOjz2B4TNDVO>2t z!X~JHT1Oz*T}IXe47w7@+;?2UmpT-uaF_G!mb?oeeTUOClMJOdokZMQqCOdYx4T~U zF?g?6WMt7&*#3$sRJ-$Bk|>SF=(rzH0*|l0{qjohODQ}Y+PAAQv-2`^pR7o+tq-{$ zbn7MS@6XL^?O|CX^r*n*EljB>0)_o{y4}2R_Ljr2&*A%Lz?g81BqH>Nbh%ycMB0Rl zP@`;#(BK7mV}k^tLE0uNopS8z8>X7^^p#0@S)`=EFP;C4~nb|qgSNU2T z(JFUN54x*`c+W3%0dvVWH8(dmX+gVEJJw#K;H&YbC-Bde>>^xfsMgo5?fqNr%}xAJ zQwC+gsIzZKJx9vk@P;6jP8SYi2E3PQaX%12Bkothu7baBLeHMe-{$5}1QF4-o`R@w zLEp*=&SW?gv*%uT&8U${x*Y7OO3+0(d5mhFeNclSCd$m4z+rBFzeL5HOD|Ig7y+YI zGV>a6n8Wxsb|*91jkm|sa`ix1ydv+Qm-r9i6SqIBL{E2$Zdf7gMq{?m0jtNk9f(9! zrPG2T)J1yHP>}z=VQomBzXX0nAF*c^$vTmKV*DRgjb8xIjyjY-bXS_{RY|bE*Ir>o z#6H!I3wA!4`LdC0U!`X9fOTe;Wgz+}!0*;-cee7f`EmCzuO!e Tx!`tS=>Uw0HB@QjegA&|jZS=1 literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/TA_android/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..5c958c271b6a5b1920df4c6b65eadd2c86e8acac GIT binary patch literal 2615 zcmchZdpOe#8^?c74&fmdp%6w+ONQF8X?RAF;}SXbSPl_#C}lD{9*2eW6p7|gVDw|uj_N)H{4xM$jKa#0RTYG@gy3v zQzQQkDaoCDE7Y3~0Mc8IXj{*Ok|knFuD`uTS0_u8I<#8xHo%6B$PkmhCSfX(L`hYW z)slm0CFyIM4uAfT?zKJUgCT2&!uP(CUpGcAKUS6Bc6XolreZR{5439tdjSC@^ak*Ci<<_bLNHJ<%gO=2S z)~6{ThRPG3fRMM~8gIUS`LY7c1W&KKNdWqhO}}WJ3P2kWXscwu9yi#DMn}8On`ZZX z;`}yq6e!vaoNx)5dT-w^Q#;#dke#_I5P3^VO2T?#KSFiDgRpC44sI&9v4;@0T;fc| zSb~6-4D2uW8qdTu)1M&i?oFTpYMA&dx70;(3|uD%D0BD%)B;~HtvE~p8mt}v{DNcK z=>R|;9DZSyCI(#PEwvBWoTmxyN~G4?5h(cS&Pjg99HvS3vNhvxsO(cP=_Z=`L!m7C zk4TVL$PvIllW^~*4)2v!xCRiT4NkTKwQBlu)qd;humD+G9CIo2jZ}o~8wl5WA9H@B z9B2NqDwdB`@|u4JtXKj?rIDImQ?oes?W`w0yQ@PoaAg-Zs#*CjQw5?gGcz-PM=ft}^y4+~Z;M${prr`TnuExguh=m-X3;=7XZkySyY|MS(bGeCRxFK|a+^TQ zByj1lphYea6M2Uh**j*6UYnqn&gh2wU@?6zgy&K~sG}jvC3xa(?n-3=gvzWI>yoGm zpxh~^P5E-O;#xma?mC6IHSy9tY5Kk%%G9O?i@fOx#Cda-%Vh!84x1Q1Ouhmt=mI5NL8Vn5@0J_ca=&g3>WJNov! z?s`@S1y2}~J6xRvafh83(=k>}- zG}7qya(F%5m9>|F4)ehh64b#*bV!;KwlQ^>Z$G39w~KhfQ*ZjV@JAU0i*f?HxI5h0(%5hycPMEZl}3OWkOzj?{?uD}&qUe#AcX>2%F@f# z?pP5L6y@7?CH#buAOM`$42!OPo94BzSCyMh3d83wT@TL<`b@9Y!|mpXlE8@-H|AU+ z#)i3sbCD4dhza^hD5qvnR~yER1NKZ+g`$DzVi+xzXKVaecR>Vg)F3_JRdR z?b~Pup_GsS=J+$!=ahQKz=MKvwPqcuG@Wz>Z(Y+HlR}}8b!n_&cJw}ylCHqgHO;Q@ z<zk`8dI*VMWsM6a*+^r$_muCr3qvZm*`UE{b(?W30~3&Q6Uc(Rd8|?(@gX zQJvM*93|~;o`ZwK6C))V;%VH3!uLJkM5M7S$h$b9hYCe^^bf2+$ZThF@eofw-L$tb z{@OK7H#DB`w!&b;!Ow59N3ml-I9vb)Zyd4TL``F~A+1F|r3i9H%(7;0I{d$)8*I%@hc)ff< zg4GLm1LX6#`M$kiwjKKE2S~)LPoFH3TgPF!S-RpPJBp1FSrly^Pbcia-%Pu^4O6pr z>&52V%XS2aCFiKb8KUY2d}je(`aEi~WmvbW(fr2vBeQBuO&#nZfN?TTH(=HtCDIoZ zOf}9y7wp1x(zGm0WM7ZkDwL3#lg(~i`)Hm=iZ8y3U6{-ucwaADSLq!i`*NRwJj88R zQZbLm16BA@)-b8G*CTk>>(_;gy1g-{T(+!p8~rK_+J^ZZtxh#W6c-?3rh@{w$zb9=*%mC_v1lQj(+^fR4LKgu}P#|Ph5@<|45 zhXf)kj;Q5Zp0gh1Vp!N0Jqjvsj$X#W1q1}>ANFYqj<0B&vw&#>kaPu<`u_c`w4b10 zq{6VA9f6oMy-k*Owny_(-w+Y}9mu#U*+Y;F^S>T1p*`21w$Fw1rN<7M6k-l4cop`~ zFP}u!cF~S6d4Lnm@U|HWosZX5%AvBnLnI-_QMkz(_ZKtWVYlVAFalRxB5tle)~u+Y&%M&-hm z>&A}6^7V0unRXhuGud;*+Tuy5F@Z!~$D5oBn?l+q(~}tX=N5 TO6%Ww2mwcXSM(FRz_kAW&B+3g literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/drawable-v21/launch_background.xml b/TA_android/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/TA_android/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/TA_android/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/TA_android/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..44e3cfddef24b1203140c88e57834f7ab6f53ae5 GIT binary patch literal 4776 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 U-kN^;Uj<6Q#_|@Z$^sJmAAwyA>Hq)$ literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/TA_android/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..c402841db8f61547fd66fd218a759e14df714905 GIT binary patch literal 6828 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 m{@(P3!M}!rCM&5VQ6g>_@c#j=JmOmb literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/drawable/launch_background.xml b/TA_android/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/TA_android/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/TA_android/android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml b/TA_android/android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml new file mode 100644 index 0000000..c79c58a --- /dev/null +++ b/TA_android/android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/TA_android/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/TA_android/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/TA_android/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a986eab6a88c1f41624cbf49446f29dcab49ea GIT binary patch literal 1903 zcma)-c`(~~AIE>xk#*En*0M!Wb)>YaXoNOa>%PylD{)2CxsIUXC`y)=OxY$?L5ot9 ztYfhvC`DHu57r_QXM?mGM`#IE$&+WE|DW0K%=i15`ObW1KJ)&(-t#W-aI=?{Qj-Dz zK-SU0&P!Mw{(C_Z!q<1J-5vlW%^mGvKB=UwviNAFx$g%0Lm=|41?t&ah|=&FOtBB4 zo9ff77f~tw6cp{(b8*GP$ILgycg894JzxA>t5@5L8MJ$(Zw2N04ad#w08&u<-P{#Q zxVq6#6`syUlqXJ)!lgkCZ_ahxRbsH|?{=jod^sE+YSo$bB?@o5?|6NY!s`Qzjh%%b zW=L`croG(h~KN7cu-9_tBkUC-JN5W>GW6Eum_ti z!GTz;l@7?Z7c8sb9F~4-CZI zAkPUL&J5R|WD4%If$>DEl^u@J0bu(fn@K9SuuXz2>OGjOOP>!jy(@1UXIS{>-VaK@ z2((|0j*Kj+YijmO097Ib+Rc7VSJaB+LPk-yn2&CefUsR%*)kNdJfcbU`6aFG?+nkjm=e42vX zYXX6AA$e!%gqSeeQusUoOn57&Ty*OMc|lSMKZ+KI9TKbc%^gel(!j&S8b_s~TlS~2 z2V6bR#82Dr{#d6!2EQ8Oe{*teO;^KuT1Q7mp!?es)ICwF;izGfuBw`vnsDkTsb=R( z|6t2X~V~N{KuZCF4A_57Af8$R^T=agM_)0rsz76%Pv9Xcj z_c{QUuGKVin|Mb~xjl8F(mJ=MrY7|FwoWp6C(p+ag9NKsod*q8(G)0#Il>MV3o|n_ z`qse%+BzhIl6<>aML1U`?!xNemn4XF!iUKhr^FKmc6e37jqj+-Na&ThAi(~cjUZc4 zvlMPfb7kGx-`{_$f>GvDH~U`LlX1Ds#Z3s(iRi{gZAuuNA3#9$5+L6Hru!-+9qpl@ zp6;a#anbA)p^zqyTj6MQe>>gbmA1aBOkeXz#+b;szT*FkNdEmLjvPX3W`RM1=HNf@b-;!y_&}BnL@#`5?CWea?&}I$jC>_w>=UQ+cS^$ z*72?`F6ndzqi1w0SyK>6_KD<`jg2|E_Wc?JOBS)-L0W@pHnmd`LBfMb(@~Y-3(Y|? z850uaD_$Qc|AN+KFV`F2z4U8Ni)A=XI(m1|rB^#&n_?^!8qt=_Bj`-e#C~_;fi56yR@j30J z`h6*TqRKt1l+7Q>k&u+c6~?N{iiysDwo6IjX(lvGgEjCM1dS^*pF1Yl$5w><-p$Yn z))@(*)wcsF$#4dP(Px>my?~=qsaEv@ur(yi)~QOe*iickLLgY literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/TA_android/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uo6s72dVVKYvge`pH9KU)7#5JEOEVo3eNfehK~9}QII zAh)ryg*kkIpwkVR>{c>a#7?%gBd$bo-l!M1qr;24TV8DM)Ql%>iW9pz6F6G#3&->P ze$UJA_u-zmbnuKTUFrmql?))YWB{op14u0yKx)YVQcDJaLQyo0=lR`#X$L&d$Lm_H zR)rvlieZ>&Dq^PuU}$K_N)W`b&*zIA*51+4QB4rU53t_T)6-U3TAJV5+WKB9Vy6Va zU@%;)sHiyC*4AdHC@Pfj<2bG=EG*R5)zzJgL?VDB$)7G?zHFf=%Abn3AccECapA%R z^V-^4i{I~G0sy3ym6d4$0D1tx9sodj>C&Ygnx?g}4E8ffQMR8(je78Y2^0Rn*l zH#vMB+8xDtKU~FtGp0LN`xhskyS6*K3&&kO-d;k9Ztz=`T1Ymf0_?_wL z=^qbk69ge~GAXQ9YbO98^zh-s)lew(GmhiM6h#G+iJcMvjYgA`mzSqtSvGdC4af2G z`^=p6_4T`zm6Z)V&+oZhuGZ4h($_{tM#g!b7Y>d+ic$g)i^bB5i;FcZ%l>0M<2ask z<;s<}5_T{cykoUm-+;+O`|8!JU+DGvlI`tn@wl;*1~_x(j21zV7tLn#sY9Bx+-~=0 z`|JnJ&CPZ2bGzMNE-o$x0)fD<$;3|@U}a^6wcG6_542OR4Ns~FbsjGM>HDU zWf*1$Ji3e&JkQ5Bt5&O3vMjp?`=TfsuP4T17?u@@L`0TlcOKjESTs$?ZJkc1WEf@- z&H?v?N~KajzbJ|^ScfHy&vD$&{&|lKkdcw0s;a7b*=#l&uU)$~%rMMKLqkJJdwaXd zVzI=R%*e=y#b`8s3JVPOUO>g(%^($mugolcj@Fw6t^clHf=QZFef!5t3A`x6rrV0?W1 zZLilmpjNAu3WWk;SvLN5$j;72o0^(l!Z1vKaC}0sSS+oepkOyUI~zo!hrhm$ya&{3 zb=v9Er!ktQH+p({OufCm6Hn`#o0}^X78Yh242Bo{e*bOgTU%S>1wr7IN@aZcMWfLW zNs_mlo0}8&1Y1;81RsD8!r^cna%pMlo+ygBI-O2UQB?R?08>*_H^HOJDx<5b>vOoK zO(xSx=yN)qU&C^9b5n%B-e$ACLJ-8Q?(XhSIyySea~u~M7#Ns^ecW#M&E@6g-%KXc zS)b4Mhtui&>am|>7$!#3^j(X^a=xITKuwb5GK!)ww}98{{qt$b9|>T7em;KH(=`3$ zAI{9o+=C@ak~A#grX~o&lW6C8eup54@AuCG&wN;pj*j~Fk6m0`q!WE^+_-V)z#O;! zE5GOW7=2bG14u0yKx)YVQcDJqS~7stk^!Wa3?Q}s26_7^`L;YY&Hw-a07*qoM6N<$ Ef+`e|X#fBK literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/TA_android/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..09d4391482be68e9e4a07fab769b5de337d16eb1 GIT binary patch literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!iOI#yLg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+5i=O3-AeX1=1l$e`s#|#^}+&7(N@w0CIr{$Oe+Uk^K-ZP~83C zcc@hG6rikF&NPT(23>y!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/TA_android/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..17b603d78c84e0b25cced0c0a78ef27e51416b3a GIT binary patch literal 2517 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 literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/TA_android/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/TA_android/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b49cba23d23919bc52bbeecf6f6fe91b766cdb9b GIT binary patch literal 3508 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 E0$GD)ssI20 literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/TA_android/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/TA_android/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c01e523604c85fd9e7d5d9d963af598c48bfa1a8 GIT binary patch literal 4394 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 literal 0 HcmV?d00001 diff --git a/TA_android/android/app/src/main/res/values-night/styles.xml b/TA_android/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/TA_android/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/TA_android/android/app/src/main/res/values/colors.xml b/TA_android/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..beab31f --- /dev/null +++ b/TA_android/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #000000 + \ No newline at end of file diff --git a/TA_android/android/app/src/main/res/values/styles.xml b/TA_android/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/TA_android/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/TA_android/android/app/src/profile/AndroidManifest.xml b/TA_android/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/TA_android/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/TA_android/android/build.gradle.kts b/TA_android/android/build.gradle.kts new file mode 100644 index 0000000..89176ef --- /dev/null +++ b/TA_android/android/build.gradle.kts @@ -0,0 +1,21 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/TA_android/android/gradle.properties b/TA_android/android/gradle.properties new file mode 100644 index 0000000..f018a61 --- /dev/null +++ b/TA_android/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/TA_android/android/gradle/wrapper/gradle-wrapper.properties b/TA_android/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..348c409 --- /dev/null +++ b/TA_android/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip diff --git a/TA_android/android/settings.gradle.kts b/TA_android/android/settings.gradle.kts new file mode 100644 index 0000000..a439442 --- /dev/null +++ b/TA_android/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.0" apply false + id("org.jetbrains.kotlin.android") version "1.8.22" apply false +} + +include(":app") diff --git a/TA_android/assets/.env b/TA_android/assets/.env new file mode 100644 index 0000000..e0c511a --- /dev/null +++ b/TA_android/assets/.env @@ -0,0 +1,6 @@ +# API_BASE_URL=https://api.tailors.stuffly.my.id/api +# API_IMAGE_BASE_URL=https://api.tailors.stuffly.my.id + +# API_BASE_URL=http://192.168.1.12:8000/api +# API_IMAGE_BASE_URL=http://192.168.1.12:8000 + diff --git a/TA_android/assets/images/LogoGelap.png b/TA_android/assets/images/LogoGelap.png new file mode 100644 index 0000000000000000000000000000000000000000..1cdc6cb219e15d5eb64ac4d759c9f3e62e94bdc0 GIT binary patch literal 5999 zcmcgwhdUeI*GH=@s_mDeR@K&$Xw_Cxn<7@th*2|QMQRJJqOBUOSsG%iU3*5*uU#v) z5H(XXtq~>0>-WBY!~47Ux%0WtIrq8e-g7^n^WF%o&CJNfNJB%ztgEA8LPJBFcF{k( zcIBd`Z0LwzGz>mER!ABeCf5HHTAB>>or_6Yq=~i~O~nw;`o-X~tEz!24NX-7(}@E; z4GqU-T@BUefwbH6AwD*%K|Oy+sA1ceHBOG=ZTAMMg$J~5sV(O-FcdI0A*y(FmhufA zClOQ(@Ve`@eHXc4TgV{ECBt8;Y2lev4kxQlJO5Kg#4CpT_V;cv>B-j9(8{(Esw+sX zhL{>z`&fY0Y)Wk+4wHV6HLvXIz1xP{Ya=U=#py2g^+KHU ztz+fyyXCfiwbq%wy8pB>dnFZ9Ls=5~Wd?@!*t`4|RpxEjPI{aGhc$U*9ggM-f(U#2 zsoaPCm)$*~%94mPJB@w(Juht1H+=EdhkWv5C^P^BXcyX}Oa3gfC{sV>TgM6&f8(2q zew~pqyT{+(CW+WtjB)ab)6b4#vask{A_}sA65DDyPCp`#Ss{1h>)Z`OLPE4&>1s7* z=Ubascv+AZGJvHr!z(p2DjZfRZ2F&1Bw#PWMCX(O5{?uE&MVdQORF;|Bi4!ANwy0K z+8CLr&Tp0(!SB!cn22vkdccCZJUSx#E?Z@nl*Z!>H3|PxkA|9#P7&i`|F_)X;c@h~ z=0X~#}8IAgQ({!Ii!-cX(OyYWn)fFa<3#Nt&!3@Vc*Db`0-w+zw%boXd|0WJ*w z>sLS3Dvup56{^>sCyb6h68ijbXh5MT@M{;#*~i8ak^hy?a#MM{MZjXQVq$vXMb|uE z!J!pK??b|h`{rDsmB$MJsOvOtQaZ>o;>SPsiT?n_tRaMEv{rg)Sx_Mqe4Y#sVpP{IhO_^Qxby zv#k{Gv$-+Ij?VD3MMq3zOU9PRo(vaLDR}?PR z*e}y2e*^S2SB5V6k(Q>`Xok7%>}?n&q<$Kdx{Yph9go_KURr?$w2J{phD7T%_!ulpsoDgY0*1>0bfS#}u!P^`?gN=VZr8E14GXu43Ly zdgMy=PIHA`IGB06mTEvpl?T1I;hTTF#FTwFVEzks>wy?+no z;NU^}bP0nc;P{ccgXd$X@UNadl5 zzj0jjk5EyB=kGRtW|qoXdrvbNAYx*&sH!)p*k6@oWjUU|9bi5YhH&Kz+z%=Z zdE∾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 NOji@EQK4oZ@jpOzQ9%Fz literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/LogoPutih.png b/TA_android/assets/images/LogoPutih.png new file mode 100644 index 0000000000000000000000000000000000000000..f98b82c446b77130f177bfa14a4153b3d7724686 GIT binary patch literal 6166 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 KSby{G)Bgi@dbO$m literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/avatar_default.png b/TA_android/assets/images/avatar_default.png new file mode 100644 index 0000000000000000000000000000000000000000..a181ac87a71970c862eaa0a7298d32019d132c8c GIT binary patch literal 88197 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%0DO*NZfF<>Y%yfE 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%0Dxfzi@>$q{dOdDVhXe?Eat{qtWaXtaUkC z8SCqNtwV5>*l?~{7sU5GQS-edY((b1Q`1s*FcgJ_di-LNDo)z{1do)c#PwEnFwUD9joZuqjc{F{6y+>Jj@bE3Y z9ZTQ8y%8q!b5t0nUy`MBZY&2Q>&~@-TYBlBfuIPJ#f+_!780j~teEXn;IY*z)4#-) zxa$Fb8F??w;4fTG+8SzTyu*h%HhU9+;^n_g-`*5nU7QokPhFAEMB`oe=Pgv*C1^ac zkB^brulhVMc1h=?EHg0oZ7nDbz4U4h)T+g{tLM9J6Uhox8!hSqQ9J*s`;H=w6#(`rz;N^q)%@RC6;s{2M3T?Th&fmouM+e8BWy*ZIAg zQv_rNX@)!ij^%+Uu9GH~_E+ORWjY0Y_-DJ;1-Q5l7LK^SCsnS~3}fd3TV8o!Sb;JJy6>`)!zB3)4b zW~?NruYEh?cP;E8&OHb0I$|?>xZi#8!Kfi!1;WDerd6?C?!@m4A>jFh^&|Tjrmf`% zq>db1dK3vTbYV4nKd`NGk&!+>CBo=R7rb1X`{ZHpMXlpkAWJTKi1RJN5fC6#*)Zo zyEExt>#8vJ=L`@qxUzl`w`-BLYgKm5Fx?X+x#rc$RWPNb2e zshkaw=h2r}K=8NtU622;O$NMIp=iSJ7@8!eBoa&{!8<-ORJ^~pIubmGl%TpfWl25$7Hx7F1I}P+8f$VX9>Z6U za(|%w4@#gUCPeLp#}Wf(j0Zn;A1&@C+*v`fN^W7>$%D;7U5pyhK3L8NA=t2vlu%vmw2Ff)riQ zCUbK++46Ra-!+@$%CA7v;tJ9Ii%m9n_#2jwbzgqU0_BDyr9zbGS;rQ?)qRl$;Kt{L z=gfd?Va4XA{RG4cUa#a{dVgO7q)3COvebNr)_1SG9i{kE?t3DY0f7GIE)Le5lFRo? zVn2WYIu_{cFG8Y$Cug3$kBUOYoeqP2Tt0WZa8%=6J~Oh}S*R7TX(&7L8_ZyCD*{+r zAT|V??K=Ua3+3;_8H~J6KKNzDgI<7t2l$Z^;T}MN=O6Fa$Eb`qNS-*pGZSNRo?*{uyweZF$HlC3K2Z62h?iObO_?VLyjJcpu~4Oo8Ag+gVB$`UrO097Qn@Unsps>Wk`Lk!fih-b0` zE{eEiEO!<^F9NFTzL@*~Roa`*7xeu+B#Qr}M>x3B|Am|#wRANoO9;+8ls^`8oBhX5 z;WYZp3MgkSURGZIj$D#VkhM$e!$-O&*sL}!`K2tFFlQDe!KY3Ek~%Z|9oXGSt`L4E zH|k|8TO9>-_~KhJfs3Saa%zeC_{hP%9JGi8^+ z0L7ZCj~w&{r`{J}8b>kvg1eD%z($`rUuumk5flF=vtjwz=j|5XYx>~T{xR!w#obFL z0_Vyo6?6VPQ7}eNFE3#2j4j&c8pZ$LN?gi0bHSxMU>}!{8!l|sII43hug~xoScI+0 z;$}?}t!nQXOFAvb64`HSky*dWYu1K?lW)V}tbhkmNz>6=cYQPrTH+8qCTHtg5}c0w z@RvpI1CMg4IqTtX(h!q}e6Jl#)>uVbTIKa_^t+a25xW?@2M}=opNQF&Lkb{6_aFB= z?K61Z#?5X;pJzn;gKVSt0O=pqcP*s$i9z4ePK)gQlnVZtdiZT1pWH0};^K~~lU z*NY`ev3RiXyQ-G|-h>AGxLm}2fd*DC1m^#-_nu)*Jx~1T0aQc~R0J#(E2to#NH0NA zu_1P(iv^U9^pXTrj2#seqy;RXA_S$k1VIGph!82E3WO2@gb+wba`zndEB||c&wYQN z=f2?KoSfa++0V|-&d$#6KJRh|Cp+~-^!Z(nP*3?Qn4(}LJZIbu2HDaVgQ?_8x|<&S zom!X9yWF6ET}E9G+Hdv>U*nC4!V6R(Ps-uH80bNJ$?1V}UCxBdpatipa$lf|R70Xl z{!Z#jAGq9bpv)*%4Z-%RrzPvsI}wipqaxM&>i>BJyfZ}DD%!VnPLA6H8a6*XvQM@H zv#bBVn)SyfHC#uITH}G}K8WnIzQXNjyP|4Y%wL1LHU~H%*16>2_T47|R`Yl4F*~eZ zV7lhy-{zcaU4*uMQ_&7vmNrr|sLi+o2g5H&ieK_yTa zI<^<+pjt4aTc+5k2HNmKyrWdCje-OJj(Y6hcJxjcDU|E`aEl1`_J?|vP3nIcqqS}l zQ=~(o+u^PZFt9HWE!quwjCy@$(AAI4I7QidO-kdgY;cD#cM<1tYAiHaRNvCvTt(|9*iJ8hkM<=M|>h}da#kP zG*kozs;y;_Ej1YR?93_(2os0QUG@#yxvc#9*dHog4UcM_&No!2+{Ce-kEs|S)f4d! zJDdEzOJrdWtU1`)FRZu`IEV(%Oa44E28$~}6f6x5zMj1hY@1;soU$2wbUZH^5->3j zHVi>(x_fXoZiT9e1^d^S=3Ww3guf43NQPL7a)Frwsg2CYx}EFbL@eDZ>98VDTsGz@ zTnT%#O!w&;9^BO}d{9N~j16n`fgBzr-V{!O{Zoz>lCB_fNdXTcas=$OLq1d2`XpV2 zo7qqEbD^c>%HPCw=MRlZ7g+a+uRaFLSGwZQ4DrK{;VwY929|eN3aa*zn3oB6)gRd4 z#E+T&PII2=8>QI<+Xuy4;B_7R#V4pvyJy2yVIts|&9Jr~i^{)@DcXxz01u78#nIsO zft9^f4LM!)jc}Vs$0j}W%Lm&@bd4`lMm`X**z;za%bLtXz8Eio`Lomftmn@>2dqhf zmm^v_B4+%}BiPeQ(@SwEnt+fl+&%?BH@}R6Z$nCNaCzQgqaQq}-ia((?caix z3eV5IVHUr%q70_F#v1poZjznmU-89z43GA~yyyNrm)X~_`ZxcI{$u2g7?G~3pQ$2}Q)?pAps^-$OYSO{gEZ{#XJ z1_#4AE`!s&ZuwA_S%ogEY}_n6<0CBk3zmX=1QBpP+=%MW^cxp|v&cB8&bi&Rv4*d{ zc+kvJd@Ih>!Ew9CUgA>fX1hdS^B$z|D0(HVJP`-ocQ#{r zJ8N9biU#a~r=z_>ZrcM`OikbkdkYR8V^f%=n+*u} zJ&Psfwm*IXf81-bjv^V5Mw!YI_TYcf*&qPi$Xwgee^(mhP3t+M6bGd;Qv#Id~j2xqzDflF9f#qol zJSG25eFPdh(z!69Gj(O})xWhnfiY_&5^l7D?OH;|RQH_TI=xg_zv+qKT3C+3Jga`bZI2^= zH}dT4_Q>~OTs4+9BTb~X9sgu*bE`k0XIoe;XhGwTnxA`D4kcGumCS)da6`e$LJ9}( zG`ufFoIx-x+YrHXA`97W#mn?wNYy#EK@E1exSKT&H925E z#wuN4qJ*n9?*Zl=#?3S*-)022>%O<01(#tjCSA@QX~z+<$D7n z6*fOkfO#!~r!KGmPeTKB z*3e!Uif^FPw`KkC2EG8}wPlw32ovRNw%vvq%T>I}TB+u5_8e>sg|<@L)6;V+AHuA) z!A*W0nTspdz~T!gbV+X>3~dE7%Ehp-0JcTs-zLfc**l^>Z5`a>QhfkewST|)nkRwN zU{5?vq31X*kwau|wYB7#&Wq`APq74dp|ls2g8IQil$0IYb7syb^0Smt*$417xl7W$ zU%q$ZyPWI^#P8*7micaXA_1;otD-Gf!}0m{X!-97WGl{s>%71*642Im{#$Ma4b<#D zT(fjVoiD|{lJDyRfb^|?JLi#eL<_XZ>?yf*C&b}~y9gRCm+8I>oJVK;A{K|)QqKo@ zAHjJ)g2~8e@~CUqDHXVW%YOKvR_CSLc80maXg&cV|GwQP1LS*GsNjBA-UKjoO3=`(}{7YacK2oU*6W9u)R?)JEKWhEqESSQCPHCFWt|@wZwF@-U zU6^nnkof)>_;9t*sc=PC{@ie0BY?;lhNv|5LP8O*8rGM6njD2fuA`E*H@>k*!wO%Wo$>yxesZ#H2&UIaqC&5EV@Yhvdwzd2Cs6S!C} z&CeG6Sk3w`BcQ=Dn;SYC&-aNVYW7H)NV_lTR3Y)*c|iJ}-^{l?*CQUS1tM?&wjJyKxKO*$Qxoc`-gT&?=^<4xhq(;tYV^ zNF&;|8JOS~++$lhxG6CVE>N4W!n^lQguNs6tF#Mfw_3BSU42HN*<}>m@U=*b}QGEEok_2fqj+kHQFr*>JWG;Q{Y-%9_6D ztxmFmS-cgSWPW=zB_kjCs7ZOBf}3eonFnRUey?q>;JI^3t_V1cS70!GG-&NLC77on zarSH^TKVaM>qGg!zhs!-1ntN@mBMXj|qFGCOA2lYbaYgr1lL zX!gQr@_;$vvxc#|2por!o7U6o9r~)S&3qIV0S$PJt9~nDbe(Jwxi&Voj=-Obpg*hY zh3Z`u0uR2W0)RdLa8GGnJzMC*F)HT`Rk}Rm%nL*fw)ogp0r@q6+te7=q0T|^f%x2R ziT*@uK7*1>vNDSn?MYk%uZTS$O9*a56zNOFpCK4m=gB!f+WnxGMTZnPI5vx7pVrVh zv?58xu`%p0thdHAKT`~Aqp#hDH-hULn_ZkgU(5U34lfno?q<|w^5=T1-WS_I7THc% zwAD&b;bBnW(AW((PitzY0r7d=2V#iedBIze>QkP4Z|Kw{Se=9`{bSL<_AI_G^bK6U zbr4p;&NseCwee*`ZvmaW8885*uVKr^u;Rx1fLHVPsR2pq;WH@V4Pb&=x)gu{j;fE} z$H5CdegNhNivR{mirbDBfF?KuI<-1%@}H25f)zpazcO|MWBA0be+0xq@*M;JF$o{@ zW}NengS|k^-bVf-58O2nbLzh;RDfwt(z$>9i2-pwQ~R%QSkoMVqtt&_5S-d3TnfIz zqs9rzU$7D%_*WJ<@=)juSf=>H`D%DbFZ`DooNM9o8BCHOq5lwk49_3p z|D^_7EQFJW{sR=mS?WUAf1g2goOr3)e`Q^827FIQ{G$fj_3`iu_HP*hvAnXO*nc2= zgR^`5%Wef{$NkqnF%Y2x2NqFi(Z4o=CwZR#gy|57mW0M9{?!!-Q>gX7 z7WDCGVRnrko=w*N7+0fgfVJj{}X zqTYjTN=P(dvDJz_X(uekTohvVtEKS+ZOI}R4z^#otM7>iVjW<(wKeBU3745yL^=W2 zFAHRY6+p3Ug9TW=Nzvq;9Dm8i#~BH4i&^V~blVjhw_)6kw58Vi+lh{0yT)@18ss1> z4RvsH$fjQzO30lH#_{nniWuo@hM3)jz)J|ds*;$XfIvym5+$ix&_2^(iEV<~0{bbSt=n^RO9=5WAKm!lBjw6)=9|qEX@S5VN6t zz~UJ=-)Gt-mwV86lV0h*fxkR}BnR1tiq~f;TU&A)I8v+*hi3o#odVK3{0#+=i!ZLr ztj=osQ1_P#?`tnDmNj0`unD@mu$Y6bv}=sKxO*d5qxts)-l16ju_Pgtv;POH zbIkd`PL@P&@YvwL_ar=< ziMiRyT!h?oQDu8#HCRoB95*cBa{%sIQwwP>fxB)%!Kesw&Bx=Sq-}6_sx@B77*I;k zz38IE-xmZFh~9%w<}MXmP`#J1t*9=vkPO(w1l1m1K;|B-6*QhMAafli6S9!Z1(?kG zg=D~LBUF260hwjM?1ZwOEFg0cCi7q+ne#B2%?rtZ18||*lMBe)gEg8))B-Y7a7UkC zNX8f@qrZ?0+}UeSEFiNC%%Y&I$OUA;;mQD;1rWc~fytOGBohvkv0Omr9;~x8o-ZJC z9VQd9kPO%}E2M6{kPJ9i9jZOQfXp&jcV#_WK;|M$=D|WTYhW^$7LcieRnqf?QUbPj zikAv5Kw=X(zEdEEv{1BQnQ&BFAX@*AOfMn0q~L`m!P-pv|Ggx5+Hn5qf|8J-M|7ds zz@yCt-35~W1onoh99#gzC*XkzUHr|~9Jyg7taI@Ju%}WebIn3#z$wR&^p=G+fU&x< zpxPJVfhu$Vf=n@B$re&sC;(vplrB`WPyobW_PiFbw+r^AoKIR@7X?fdN1aP6eH4o!9M40Y*uPX~d_qQYo-PZs{CaQ8LUI;pK z)L2;hDlh^CptrzKR%z;F?BQ1gQ%P>YV`b zjsg&Dv7Uhi460U267oedl!;JFr+{2SrD98|#>)Z5P*MQM3M-!fTUHfVXF#=JQmFzj zV?edx;0XjggD0>o2rp%UC*ZABfv4_JEeMHH0msyXCt#xe&%AK2hiZXuNaZQ=^bkD3 zRs&QEmS40`RLv@KXW!)gt(*0Q_nZ{8RvbwFrJH0KZxUKNWyq?f=S)V4wo< zt3~ir0r=G-_^AN=Y7zWY0DiRyekuUJS_D58fM4zZ$cqe{f(RVM>Y}h9X8Hgb25|zQ-vIbl!L4ual;WEH@8ghFFMGI$LgN|FZ2z_Khz z2Ebc=7@-Eb&|)MR8zg&yB-;&=fkjx53}6=pR#^ZwkgNhIK`3+`;PMHQ3@l@w5JQpy z=vD(4J>YFCpoSz10?9zwCMfh2NCwZ4ptk@y_`V824J3o7J%Bfm>?D%xoS@!g5C8{3 z0Jm`D8{Fju;BSzC+%`n&&Kx%uhNmTnwgAT*2|*`-8>0#y2A~yP-VO5y@jxvC;UXatXhX0k6X-4!C<*rdKs^foJF6mWCqOo! z`6H1MRDp^UL5e2>BH0L$`-^-o=)tusJqw6{_!~eDxZh%6CqCo}dgC$R2ZW&fW5&Wy z5j4gD5fF+EILQNQZ4p8w7!ZNy7Eq}fs29?uJ%KnM1B>GzE2!cB$ZEVB$pG}=<0!Z+ zb~Xh#r~PCLnhR%xfVC4j}yk4|$LQsLd$^S9vgaG$BMHK)tpgwW$Q;_8{aKfEAh7=UI1p}nA)5@B)(I1PZ@TZG&Yz`6!`A_E~? zjSzMLgu$T^fG|LP1=80iRtd-jAVN8@8x(;+7XZ3WG19{VKuhe04K1knps{cwY)3+0 zKtEA~I{?%N1QK2gh9D64Q|f{gwr!D5Pas^F@g70FiDhtM8{i@kwFt-N6eHc^4rm?u z-{b(E=D*2-ky7b5Inc!32)Va_9Jp=^kOOLB0_lny0G|PfZe0O%H5?lWL3hCDdk~S6 z?<*U_a0roWfG0R21qwX_i0nd$041W1$jM`%JPii5v3Oc#s?cjPL2Vr-4RF>LC>{7mP&0nTM@m=oiqd z;AA6!oDC>J8)-vP0l8U35Wtd_&=B(R82E@ZW|gV2Fa{}LYDFX1(FUv*NKmg4X^$z; zsEBwy28{*Vc~IzwMLvk7vJDKYKFBY%3x4^nWQu`*3~6J;e~zFM1*XUE5iH&SHxay0 z1{uTtE@U7*AtoRbAea5(ZNHTcE0yYUDRBeY08#az`@MfU z0$-o@yW^jE!{t%34fd&`rsmZ%#V*PKR4cVt`Pa@B={*|Tz5J~;w8c0Z<-gmN2zAnepCbjc)jIUOfu(|JTm62 zxEU(0Id_=)v23oI0T%)Wud_iP6@HfpG>vc2yFV{LR&xG(i37>*HA)~zz(I`82dFrA zv_1sw2dk@Z?8b0lbp*U9CYglyO`DKmLB9w9I;h6_^8(;;mYDhd@)R_qy9D$13s4rx zet%z1ffr}pim=&Wgyps@WQ2*jod2l=yqr@9MLRsA7# z1Spr6zkzui8!8?@m-_ofeJ#k%O8fI72RbOt;y2w3JAghI-1p}ND7}dYQEp?p2k3mi zK&Oqy{wYNga2#2~1y@XhFWZ4$i9r2%c?Vt=J8>Hkaf<|c{^)HCmBX)sN6h6w#kdB? zpz=xqHi|%3$jGvjae1A>f)LaKk}9{;-Fcmh^dRUM(DJGyoa7;+r4VAb%{#P$)=2@X z5t}2!SAw9&!2E(BXfe>$%8KOi|knE{pnX^ zdw;i)g#+^v7d@+eTm_m~BOsTw)Uw=$GePPZa(Px~6s2vu&!doZd*e%m)TV^J&;_ut zbzw)|IU}c9ue|1h&_G+PdoJe!F=BwjpJ^-RC~!yw9F{&N07Za)rg*(-D2?=}Vdu~% zORm*Rbaq4RdJ)DWLjN}_?tFyep5(awbe%A$6qv}R+2>^3!2VrF-@1dP#cmWcJfDks zWj)eme=1c13IN?uJze?ataATGw^+}Cw?^0T>1AjdBM@wgc6i8nk6nQdSXc6m^F|a> zH-)LGD)oNw8fQ%H3U^58vz+^f$TAw}oaXmXqk|4;| z5O145zOMlt1(n7lg&E$IkEM-bzr0#B?IhMaKd3=9d8G-30uut1wbUnBgj1`{JzWEG zj@RM+WwJyHB33~$l1Qy(_R~!$BW_bBs~YiM{=UKZZf}LHkh&5KxVxGcJy$L+WXMB+ zyVm4>PTWSrJ<4(ULQua5Tt`hxP{8}SqN7wvMQ{?qS~IGQL8skHhb3}<+O|V7qkIp$ zUUhsxzc#VEn)=YT^A9{$6dA?w+W?$PXeYrEezd|rhBgbboi*L|0a%+7auoOEslAq5 z3K;;M9@Ba!fGB}RYfry>UH}mKdAo(CMWv_|8umeFgVK(gi}$D};gux{Ge8MY%*3WS?$#%POQe?qsbLgfx)m!5Dj#WwL(y zy@zp}#so*?(=JPFhoBlT@*Eq*81pp+T_=OYdo9D#wE z6`9UlmRi{u>1ZgxUF^Y8ZZV7T=j+mj88)~ z{k=a*)&fB_*Ry@z(C;_ykkbXCK%yaNGlCTg+cn*=$9zIPE0h<7&8T8k4tg_O8qgBS zLQup?&`X(Bt5{vFs^bS-u>6J@7U^k&KDHL?I)e#s3&yfx#d9>3aP1~&%f~1jm zjk#hG{Pv;7#XeBzDp+cQoR^f)ZzqBo9dtqv=@NtAEPC5X%ghc191_%nj74C!Y$d1; zhlVXyf%{T`0Q~)xQZ>Zki^@m_QC9^OW~u-qBMOn!hg-*c_eAiN68-tC7VgaItOZ%D z`s6dxy(E%r=pFlAI{#y%Q2sW#ch5si;B9URhbywL@E<>A6VF2A*<4D|3#M-@kS_rU z1nmK-I=H4Q;~ZHpeYt3Nd9)MwSsKh^V_I9(!JSOGb(ZV+8c({$_!X_I{13Hyt$=nT z+EF=)-WAv4V8{u7G0iwIep2XOXuUzz0HgveX!Z0s0d$@nOAWFO!D$J*l09+=21l_M22bZFA6#S{3lU(zWZzFa)~<)zi})bh2%ye#*0x?W?KD z_H#VS0f7IzXIFunA5j@bH;ooW|pc>$R zIW`((jN;v+jU>`~Ee^(>j#o{}Bk{gt{Jch;!i-sRUrbpM8Qj4Fx8+(RS34$2({$xL zP8PEX>m^y3#mb%QoS%OxY{v+h4A8fU$;$i8rXM)$xv{>x&Pk0#;kS)Wu-<`;B{sx8HyUgHw1968JB zIhE$#e9O_dd1gY{|Ktw-H>bu9O68Ds^mcxRl+OH3N6OZ+8IMcppPqi9yjts>-;eu| zh%Wfpfp)u{x)D?Fpt0qXNsPPytJ7@DVoHb>R_(CP{zjVn_sY_|IOd2&)%+XF@D%;m z_D;L|!g5GFfBj;%QJnu#%d$7+!@O0kCd-V>OFoV_*Wd!!r^WgGE{s5(SWhb-Z-Y{9 z!!za}qxF5iWP*ZgMrfZsgoPi8Q9F?# znpM)o-aH&K+Q7M7G&lErWTdWw|PgS#tBh~4#YsprxQyCk-I87u4~KNiYWa0*kNx82?- zW;iI`bdm4Ttu@(EUGWL^wqf*|o5uBnc{DX+oj757{gHrm8`m5O3CG-C~RKjgVyyl3A-OHLh!kc5p1i ziEO7+1?Cs)hWWaQ%@Gu8o@tS##C>Uu{Zo`_ix{^4+H&;0rR)Nu*PV<=ui?-~^f#*C z2ziyKSJ%zmN6YeR%fI+|GsS#K8{!lA-4?3v8Mwv{I3ynXFp$i^=dQuY4R zmjrvRzzTPK$#m~Ya>rx{pX^p_YTdkKx_PR@cb4QCvMN{CU<*fSbdSk0G2Dw@lVjGX zOuLXHw1=TQT|HTTuz+}0ya$%y5jrK!ibO0ryoBYlm?a3&5&c8kFzD_R5;1AQugLd}ZD|ML|UpWF5fAKB{Tw>fg z_c*bEqFxmQJui27jU#yV z5%-FlU-@AE${o{{rS0!EX3p*PnszG;XW>X8ZsItGWOdx>ef*(y;&EJ-$MfDDT35O( zASpycqmm@tw@mkXcu)xUPFbbe_Yrj$PoOjgoh%vo$2m#~_|`Jk$xVmz-k(VwpAch9 z628kmKZL96meEnYES^fxITt;1SN{rmWt^0cz@B*Sqd0nD^P=n2ET_&}7@pw)9incA zQtt$7qU)7?4~?U~6BF>0doVb>S!PS6sV2L5^`@>=Y!0_93eQ+sFaAlF@8IQEk0G*j z<_lNRl|%0#dR#uN9&^$npqsLB)LUGGO4)_cA|>v?S}`Ke9~D{sBylgvpfk%89aD?O z_I==5&QW+lA%Wa4N9_WHiJp5O#c^CGhEB9-9|~r%A4wP5G2M@eB$E9hZ};_Nuk+eW34?ie7=c%v>~g z=XZR9g|tjOp6}JaEX}d=g#q`T1M0?_SaQZ@Xe9!w-Btx`#Wn6Ed!~9qasSBeMD--R zo!&kp)U78~`eASMd?y_nC2Be>QkSwbYmV-0r*KBzSdQ`w50BEavND`B=FprHN1v#Y zzHGNSiw9DyB0|e>8zWjwS!f(Tlp-QwmW1Ml*M&1$neRGY7z=L$F>YW|6h1XaaE_of z5}cm9fAfzw>wLO++CgXxFJ8Oy#+UaUa)gKKrt3`GLwS-PI%r-T9?sl4FQKEtZ={HM zKl;tEejl3d#}A$wF%ch4~K-CC^+rlbw3|zipfG7NgjOecQ=^7 zitDe5zJun~a;==b;tMgpVbhaOiMt)p1`h^*4%1rB7!;Sy3~ZlfQqQ3Ij}P*z@m$Wh zeD7f9#^87*)7vp>AhznaWi~Zm`SA#;=&sLCBX2SOq1BDuIJ;Igr;JxbEJOXiY#P_P z?6i!-5-#6}gYA$XDzw*$NT!Q_$KdQKoD7<|cY3J^n$=vd zdfRb2^I#>z4}BH2rhiRb?*~mv(d(#Z+y8XxGy{4+toKxjhTsnncvxb|)O8Z!+X!daCQnzkwAZ-ozIigP zx!Z28?>(g?Awu=Wu5#zEYF^!m7?u68{U~{R2Wxe~GspnL+&$N)MzU?Ai;gZ8F+5=0 z-F0YFZ)W1$sbZZ2P1djM8)5bO9A-Vrw-M_k2b8+M(n{E_HE^6L$c7@a6@;Cc0q z>^0c2XR}Zc2R+arR(VsGxIVUDlyIE!3&rR4?J{lmTNOI=TiTQD=Lfi}dIrC*w$Yg% z$T3XQZxRX$*2m)oztLYXCp1ju$Hy(?TX#vbNGcA-^!m@{MttAIjAP&IxH1&doNj!s zVeL0Q=l(u#qIJheR1<+T?iugE#8}Pj8cF||*tI2ZYHrwkEIOTU;9;mZf4l$k#HGBi zj~lxQ`+xRt95XeL{XS51T_FnZx>kF94M~kO)8Mb!JC!xxJ8O>3V4!5KGc|CD+%&aN zXPDu2_K6Z2L2=FAInkd^vhdN8LGx>;X%8(Ynr~*+?P{8r+!b3SVa+;eRLraUGWxVW z33ryYT)uN3ZA6zg}}Go4eG8kJjiyaZAhYkPQud)b|Xp8^)Ha@s??q`|0qU ze#UZ#s0Zr{PzGy540z1+cavFp?%sM;*oL3H+vt%Ok2>7y#lOuJ6?A&gee4s&Kk^H_ zX5|U|8=G&HOKu`#Vn2wBl(cv*->@DwjmR|&6v^l6ogDX!4;=aDZMR#3Ej6e(s_!M% zoTr=b#HHp($)UEX&AFDNU8_c0P|XRwAs?p*S*-4d-cqrrFSv2Wp=iuWhQG^%yFCBv zs5t4@M<=2LV@x5rKp{5{pEq~yTUCrLxv)D=mv>F#s)U4-jb287NA*PAi-ac*|D zGb989F6DgIa4cE-(j)o^hL_42Sy3N>p1UnIXQqRmlsZRF1V^isv+p)9F-FGj4Dt{b zGpzowh1ebc$WBiFEGGHoBg31-lDvIf^$7AUd)*X176-L<-q$ucUxROy6rLtfSlv5k z*xA0v?xU*>U$w*gx$a8#ej@u*K=qVkG z7h3-W%h42)ph&yn8wi(2`-8LeDIRzkErV|N*79#U`e+GD`nY+rhXpycG=kOAYu*i_ zx+UzVe9>)Mas85f3&ODal*FX$1|%3x!Fh7H^$Xj_-pZwy}+nffeb^8W_7z{Ua(&Dm88krlI zKAB#L`#N4O&>1w`ztYVQCHWcWUq$Qo3yCmb&(IWO8(60Kd+Lh_1(w}0{ltNK?|C;8 zHn_QS%%?Ho6LWCLKi;pJGpFU??Iy(Mac~=wg)aXdu)}yPa$;_Jp=?1tkNy4qk9+~H zXJ#HbU%R)zzxBSW$CmD_%FsC0uxjVcRMjKK9=!R8au)^SlR0z~XSm6esrg7$Ji|Vb zIn;X=`;^Zla|`6lT@0^p$86LYKN;7xR(N2ZOskY3?ET`@9Ed@DR= zSn}nP>7unSQJpK*iqZP>Y|qhW$JL^gPHqvWmg|)Fe(NnS8)h;KMrdpwN7aNJBN}GD zU63~vtr<5u=^6a<2ygJ_xWw3d?10&I8z!bI!oR*}X8x?ILhF!F^e5CzO&Y)4q4HK! zI#(;TgE=U(0yW;b0>@zc4HU{3_1ex0_O>t9iT`z<%TAYSwlU-&8lNF(>&6Qd+;x- z@rIGX>ZLf^tX6;b)$U5U0abZ&8;UMJqcHi2>&%QWLCuoH>!?NtW!riya!0d_{IK?8 zV=Mijl;6|-(gJ1?@zEPb`1XS2i0`6%HNT6oGrvtUxoL%W3MA|=Jtd#izK`fiW* z;m_s_(e3x_HRe;ggF3pLAL~|uMbO8G_wPNU@16Ht-G|Q}8hwO6D%HwT(C68J>+poT z`%OcxrLg(+kKSSsUl)E>J>>%>3&FW5^n&JHCG?$X;+x}HUn@!1F7N=SU!v&jq^^H{#)i4z2Lb|lA zID-2mLotrUu;)GwXh@th7x zvbB2DHJ!>w2h?x)AfEoCh(z=-O(6QQFu@*E6Q!E@#q{0=jhR=(a@{YrgJa4M?EBs1 zLt@z@9ez1_?qU2;-}AO{KkfNh%e!M3BqI0LXTNDtIg->>g8SkXJbDvT5MIuOt@gX< z0d27tA1LYWuDUG^8;Pj6ldpDqb!WI6g>@O^&7DEr#k|}3)2qzahIs5^Y^c!#zCpg7 zoCjY`wINxXQ(UN@P~sZEV8#=V_wsJ=hL9?eC|d`hzj;H!0gO{qKT z_FX)vnpdyHhPNo3gt*fxCGnfiHMIWtD9C2}(HWHz^w}B`0Tssk z;_!9PNn?+L^hUJKwdhZSZSt3TA2Y-|!e~77CiZ)JN2TtL=UKNa~B2t;(jt*KIs$HpqfU^xx}6oaL=eM(~j_UDZ*Z$eCG&z+@{qDH{uP8 z$Jf6YC9n;H)J&mG@FazK8rbIPaR7+hv(p@VbiIc z(UD*f8KprTl8{Bs4;*B<9rk97#(Q>>(8c4+GCY_j*x+9+ttfkx7>P57{^m|u9T)7< z+|hjBCM5LroSMPU54551JQ;<3^u(=LPk$Wqp^~*-TLbNbSsDJ7>|CiJ~P(O+X%Qd@4#NZ#5*rx3$X=?xLsvi^4KhNZ54{v?84hwFG>V9;R95(SI; z(*bY!9RraVR~|3K$Rk38JC%uNI|!D706gFmH(#|G!Tx%8QEpAir z*Os%BD=e}KiKYBx zr|iu~);5}>t4Y}Ush^U$`Ud=v(WU`MDS0Cow{E%z6@?w%su2IATb8wjV{nDxbi*^) zJFaA9+AJrBL-yAR*d6arqR|@et|NK}zU}WxDae<8iS?d$onqCl6kje&Ffh2zPg@T4 zA>JIrL!F!i^e(QSax&qZIaBS??wc6&tBk>%g8b$moQH}NZH}Dp^+^)wYHbPk?VhtY z95pUyjJh?I^+$|LXkF$2m8P}_P*Hn-_5Wd2U8Z;nhVNtx|wRYNl36on7C@Y~IzfGja`Hb})`Vo-Ay_w`G z{PiW=4{MpvqUL7houWh1RqK-!E}l(%LHtpaufT~yHTPhAg9W+ooYFdY$pbDYXLxb5 z^wET!3Rw24+`Pnn5|@adM)EXBpLX=Tp)BXC5+x)&@YuO7=i}h8`vQpX^u{c!aQflV z$dCGhe|$L-$6jHAgEd8P;NT0xY|~iw+G!SJ%!_u#?$Ctu6{B`$D`pAzUFDaE zAs0z^k5zd=A>LEHXNH%P7~n01h|q` zKLM+%3OUo9r!$;tWvvFcuoWg9Zm<1lnd64Hx+;4jTu5lf^tvfZrjL8_KMQU)$aZ6o z0wv>iTyx~*&`eNTPW=$$F5}vEp&-(=wwn(tunFn(mYoqsOT93~X8GTv^)D}_;x=^b zLHB>W@86p4q|lBJ!G2a2TF0xcd&U~8Y$FsfmyM>?98B!m-_wnH-EoQjU3GlMOSlSg z7csx=nUN~2JmoRdU}dP2H*?+Cqdcd-O{u``gHmG=sknQMccepHezpMj#kqkY_jK(w ziEY@g1I(T@ldBC{L+k=)UeQ!VOYd7kgcF&$j`R}ETRZKb!EH${DnoVoUm~7x_ShMH zH(*9JA)mK#+JGi1fb>-5;{|B%B_-A|oJ0GtfikRyGz~VVQJOhMxu;CI)%T<0%U0Vy zVni`vfYP#);8Rl6^w{XMF^PE8hIE8GzTY=E(4aT`$}b$s+qX~q{li2D9;CC zJ8ie1c*aH6voE8G8w7hq;I?$%nlkBbbi0c@C82U1yE7?Id*+!(th(b?kErJ8t?L!L zE4bmIKgPS<6Vfeiqum^hEKuwjotBWf(%j8mp&MHQw9=G2zC0}4UTD@s0Ko_hF|hEr zX_U3|xATh`baBM#ZXWuZeC+7y;eLe^=)k+2mh74Dn~N5F2d~zQCCiYwUq_+G%;TRCdrk=ij^7;qAn4ED* zHgl2mL6k1X*|^(gm?Ldh6BdobR4tdOsxW-<=@Gh6;Gbev<_sy<7bvaIr9tXxS5(P)i+RO60`BVox>9oU}ey^Sf>9)zb zOu6YOx2g?h)>R4eT0$|0(AZ1+n`s~9Pj@dvFFhWe;z@p<&)2h5AZwE)2z5#JT)S`fUZ?8TovSc#KWE5^B&TpK)Ar$0a zn1S`4>id3MnVzrI^>xy`EdKeDm7*{RFCaJI(ZJhMTY!*Mz!Nc$)I8%b{F4 zxPe5im>YEJ`uYTIM=|jHa@ds+@??_zlpCQedhDQK=qEedAfL;=eggfS_O$MU6O|~P z>QNzeL>L3UrIb*Xm#BRNTX|)K*dx_X8LEdW4gG1fSGJmw<}4}sMvwUS(RO*uWk`|3 zlC;&S+-gfPb5$?WCtLPJ5JCQ2z|7~__08=ZvW>zc&J|jV?Nr%Fjt6KcB;;cB#qcEA znIsWxX^U?h({>=9u0+W+Ml{bBwG2oNIgGJ{8WKK}x!p_inZ$*A{iN*<+(>QnVyB5xqXIaye5K+cZ6`HE6PrR9w9^zC9@~ z55phqdnHTxf|*a%)k>?Oth{aHLi@FR6|(8&n6l%iYq&rHxaJr=`cdEdWXV%kzsh%& zN4+D=It}~kC0J8}qx-Qvr&Es`x`+V?k=TwG*pKC z`1==yE?J@SbK&+Aedm_-TJeeGt}mm?^dHROl~0rl2`yc!7^xQ1>Dg35NAP4>G&<6w zcgm*PDRC#n$+;)#{JEKW zWrGCQ+q`dNM&SJFUGZh>DFff<@0!OK@<}E7)*jM_W%dN|^UmEdaO-cD9=X)tU$#@x zY{{aFjTXZ>eghNwJNNW*XU{HLDTwx{$=FMH?tO?&kP7s=!J*zfaxczfoxy&-nZ)Ku zM`?XIE^jV}NG$K# zcX+1j*U=P{ ze^%+P8Km7#<)jR4=KSTntOIHJGB}>$$F%Ng?ZS|pwu>cvqr8Gj89Ti&VqSQd(R{oe zMJ1Cryhg{I5rz;^=W}tlhwX*rWSvAL18?KU8 zb^j7ubU`&tJd?1qdN3_LG@H(vb8dH@qO>0Huvgg;*SlV+dB~Eo1w+ zQj*~ruQvVwK1hiXRp|}Hh;pU4?t687dT1 z-It;RiUa%ZpGTKA2h;XnXTR{?5v^@18)U5{w^Kqrw96*7Z73< z;XBh#k@jOX&5eDn!;Yer4cOsD?854fZ!`+3VPH1F|I=sOp5X&3aa<0&VQB1ngNEw9 zhO~k)Qbe@u_ro>y&zJ&Tszq3)z|R;MA@-Hi{1KZo+tu^+uQQo_PE^*|0di8ryffZa zbK)G0&eOLYS-1NJ#^qO?0;&7uKz27`;JCAlh3{EP;30{!7GX-EA#bs9CCe z3G$9isF_%?>gjeN>HsyZ7#}i{wd8`7pxg!f_0P;SKg9FgpQotCjy4LX4!cWHuNBl) zS?lg0ap(6eW~V>Vc4}jEjg<$ ze3XPe9%68f{?b>!hN)Ycu}H6!n7cjhQ(=#<=c146Y}^OmKOeQd$(x?b_RlZ8-eVM5 zLFfw+L=OnDl&3yY=EuAE2h{q!dZ3|G$Bo{5#02Q&=_gru>jlZ5)uY{;nHu8yV$hTO z^-7N;l$GOtwGkL57DT{u+(X9*!*A*1-s4A=8iz*ANUig%0HqiS82e?!TnnBr~hPfjH#zVon=Q=dM{LBX&_u_C!z z4cWiWn*8{6&#-;MktEWwBtk&X)D(GFkt*T2ytG8JId)|Y-S2RPyl+NgyD8g+TRs@U zH{_qa{ED;vn4O#Z?Ab0CMh;dy+O`$?c^?)%=_}1|rSBcBRNZgBMAbxwswPQIBMBVf z1#WMQTSe(zH|_j7|AV&a=*}KLvzgOb_PtCkZQNTe6e0JLd2qzz*7X9p+97jij~88X z8xK(!{<4?`oqq@ucD!<$TW@bbi@DUWb1}PS5xZL02-8Yy8($OCCH{)!K63xOleg4Q z?&hAl*YquQQ#`Y#w7@x9`FL;c})>9O>siZ2^19- z5Sd>rpJ%Q2hxaddTg$av%k@3`ob%cH?6ddh9QQ$MrWB4$#PEa>h0_ZN0{X`GB&e|FfMT4&51DC285(E-LhXmVp+qO%I6W!pD#v7TYi>Q+ z?oSB%4pPdJKLMqjlla!bwBVj8#d1zy*|$}TIvuMPt6YvogD^_w()x`OlyQe>^#O0T z%ky(Duu;P!0=@I8q0y8(Q~HE^GumDIynTTm#)MBA$22bkYtgZpIf-=Lwj1F(!s>1}x zT$h)Qr*2m_r{$B%hNj@{OtnWZvcN5WJk>3zrtgAAW&+t6%3e<6UsyRRUD2ccW@b0* zk5|7K++a8o0DKakM{b*P+S1u*$9Wj=C5i70SzKJT>Bm;#+7dN78UH<1#D;_^!34)5 z-1;g!iT|i?c=>2HGQk=G8-CU2Gi>B;DXFVDRcF8%_|6|vAk6K}bdSj9SEH>)_F;%U z9gWOGTrNH|?3+#|>oVo*s48)Lx z>Ss9O_gm9m&w#sdlTDcIS+6M_D4%Z|jHct!3h&f@TIb}H*UrL1a+u|6zHpt8(z~7A zat3~~n^K0&dt1}KTGI1n{kv%>HgdQ`aA~~n)m^?L;}Ax0s9obETb;W5B)ER@kXDk) z!H!kZ(jOl5Tmc+I))o~Pwx&$`7gyQ(9ov$XglSfy^*m8&^18W3GQ@;)$`oP)KD(KA z5@$dG_P{HHZ6=h3F6QUis@0N-L}`B>BIG?a%R9c_LQ8_@E3*s<**N%V0Dr=LbE7yen#mO8JNyisrq?HrCtnDj%Qeio%L-CUQ~0$Nxs+rc!8 zjf`yD2i%C=iqfeOVq%~^zB`v%-cF(VM2gmzS8UoPUBMRrh%>iSNOkJF-k4Ut3qJ^?V{R*aZu5kF*DH5{eITotaeZQuyYa&#N8iz;=&6GI85N|1L~g4 zF+=a?Z3@qnMFsje>T{zNfOxd?%%n+V^PY-%=F=N@k%a`iK7})`3 zf&$Zw$iWfEh#sbX=9Q0KsK*ED{lCe6p+BI!LZuR8{PNWB&9=eH$7nSO;LQm=tekHUjCq%V8~{{;Zez z;@|DM?_1Uhd-t;okIaVsZH*dl=(~|um}LcF5wZyn;7_VlKk2D7A6%H8`^*R*c@?uY zUWs@Xj@tIyN)&Of02F-T5+|x_Xr@G&=Tctyal@^`rw+)S^+vH|y~tg*G{jaz9IH|gbxGK-?1g$bPmNaw^~Bil0^tluQ< zn~|Np$|n@A5k6F)&U>h@b+tOnI{DpUD0!FjASKmsM&K?mIqL%w3mE=u#SdDas9K=n z0RXYua{3XRaY51wi?iBQKVeq-J7SLLcqrEwA&Eu3!d`BpCHMiO>)9VaaCou09RV8E z;)4~9!^n{hvC5u)PpXfyLob?YT$;_e<2c^QQ;4g4n2Z=eVHryuZ>xsk>mL}Ljg5yWWlGYhbs^xS%N5|6X$ASIfQ_hH#A zB5&;($49s2Wgt;HD_C3xl|K}1O;;e$&GX$fyA14-{ba_ri6Bk`(5b3^^{AN2|K#21 znlqv~+IqiuFYquP@LPh+c*Swuqg;=|R&7q-@}ezCv4cf^F%{}DS+f!HG`B~Ex;Gqm zW~kqfBFa$6%F-Q~)g`y&9HDi?uf8zbpw1;9hf*VgcpEy={RqAI#nIhS38CHy!b&SEjWnt4NO4|^8v%qXq3%>mo5kp_Mhqpw>GkVncR0q- z>#$$F7$GT^4O%M^*dxJi51u$D(2qm^9z2*9)nq>FlJbz(s&>ZWH@R*xbfPa?(YBjf zJ`hZDMH=oW-h%+adc}tMMlOA2HDS>Enp$qx%A1H-iSDZJ$>!F>~+a#w0QO zP6>5+rmm9{fc85rL{)2TWKe*Wc6&LaLqGaFBlZs3H z9~tDKoV6L`3D`|hll z49Y9BW}|!Nwrpu0Pg2~ob47n%f|~CpO!5JGx^Kx=O5a@94a=MKv#QKv%3g~@1~o&| zrOBUNV(CN#9lztgs3vC=y$CF`xw%eb7_t%#?RJsIYxo$OsDRftGrIPNy8eEDB<$=C zu>6%~uDjwa{@W|_=uAo&HeIVAxzd z0oYUiq*<65?zoIeqf^wKmVUwT!4o`N_4qiN*;Dq;_wCI)w=o<*12&X;>1*xAck9~T_8WTM{r02n2RXqm%5DMMSlpMsL z=m4`9Z_q7$L;;VEL#9E!mj%X?kqNjJkpDfdW{Pknexs<_V*WJcu@|7_a|hC|O9pC8 zHatQE^My)VnH9=|qSNV94&Fw84IMFved~C;k}bZxn;EzuV0B?Mwwi+TC87#9m6=-- zJLlh{63mu~oc=>OcfI>xNlTHgFP(h6SpnR4x0GIJ33t3MZg!wJv5vTC%a?cDo(>8s zZwC?T2YSrdpg^z~ZNDQ$pkOo5vh9tS;ykV1eii@8YeK-`{}^mBYSf@s{aFx9GsQ~- ztzO>kQyX=|jydsiR&&Q{L{Fk$DFO?3kIEL1RjWbqkpzm)aurou9=XvGJB`!U3tnev*lLmL9(%` zjylnmmp-?VZxm~PEY{n}pO3(;#?w{M@^zn%JWwk?qOk&#;n{rI^Y99xKsQj98Y~PK zm_toU@dMl4GbHw|b=C}f0*o(;faS(#2>XK!f5Wpp?w_#&g?^$=yozv3JK@b{3!yUz+=z{i}gZ7&W+zC z8KbVan!$e#KkH_`#eBz=-cy`otjx!`JFB8#E8hl_k<|Qg5lcLQ`eWArWEpn;9E=L6 zwZ_B_m&+vQA@B``I-M9NQO8y^B@iWf(#MyTycXw)V(Lr zBC>xvdL5h9Qn;R-o2uWz(5Pmwo!OP1g+;`3y!ECIIS-P|BL}-0*(`GdMDB4tWJM>; zWHC>@+=^(*7B7$ulV(uIwKkN2!Sn^u>)KOqa)*6@*r2brGl05tD>KgbJ`f^~l~6hF zVvEZ5J5R~4ZN9ImbJxCg8VFlLr)^?(sl+3bTjQ5rX9gjaVv@J!w=C(Z$w>xt(Wd=o zC>d{j@z`zdGnPH@;xM=Kg4E(=#YerI<0PtKuZkpQs$qOf_TVOq2Fn$nxiusDPQF^n zi1gUIwY}sk*YY}#X-<-bVZP1_^i0O`9!J7h?dtt13hH^lB!7SF(yY=*%B8?Ivx>$> zbAJO_F(JhtqRHr(95`RxANs|g_=fCs%6QHuEU)6I=(p*y*sYMXO39be0f0rreA>Yd8uE^6 zc#jKnG97xrO!ePF8qw6Uh*H1bcP@z)Rx0B@Mi3T!CX!-8L^QQOCG3pXtKR)*t8_OB zHOZ;oE}XV%E34|rJ!}t~)@=H$pv-WB8)`)=<4hAlf(EkZ@t7X6&ja!Iv7H+y?i*f{ ztOLKzMlT7vi`!!#(?cG*I+`bvI5sTw#7mjtVTXl-N%+2F1a(XP1W_AscqJnscOKrB zWu^2)0FBc)rhYDc4A!xKbBOPV!QobnuZ4JBv3s@sLhBon{ua3oy?kIsGkGO>`!Qr( zhR%H`hdy<`FSfDXMvwGxGZ%vq)>#A{2)^6HMr|zE29r1sAPr2abFU(y8E4SG3|8b= z&i>yuhBa0~VQ7l%!p-{v=u%$g=A(1xQ5u_@NjR10(-L0S)u3!*%~9aNf<^NFHNrLp ztz252;!sb_qrX0yRd}u@;DzGZevWW(>Jhg^^ui5QTtE)>WO`pkk!hPHtfN^(6s~rn zpD!*}NA3#U@x*YUF}-H>q#EB2uvD?q`(%GkU2LwVN}RR|Cu#{coUfb?TbdKSbSU#J z2tE~$X{Sr~J)Hu{1UUod^2w*G45mz_)a4`%xU3iT2;!oA_V z_jrWjho>>O_P6(|NU}|FGr$pEZN_0@Zu5|6?}WQ>`gh?J`*)2ip)28^x*uVbvviry zEw8Z*%aGc$=i>WQV)xH%y4l5yH6wgU%}O%evUyS@I{Cs09A;*WSUOT#b~$??MH4)* z4`D^@fo>*I=Dig%Z>o3$g;?IWvw!H6I>^Pm-Oa(gZ|MVrA<(J^1ME_MJ8HMb#jsibHMEEz&zqF#_yt|& zBVp35F~$eAYuM(lRH)SG{5VVeCIl!b81MS3v)$A~p*MGVFVOd^cpFk(b|W)Lt@NHd zv{!OSMyCwl^!3rO@cSK7aD$+S|~jyrx#X3$|?`sja9kqz`4RW9C5kFkbdL^nu^8>+gCp1#?(ZUl4s_uz=%9AI{BJYZB;2; zrvUPdW~H0_nYRndlk;*}%7b-wkfihHKy_4F;jygs{rm@`lk=6;K+0Q(235j6T)@|* zMc-sA(0t9n8h;xFCXKP9g&Y8pIDf}$RR-LV)=ckPHT>f&0sEAEro8Z$3-MV}-`^0K zs;y)6^g6ipdagjReXVLFK3&tPP&^$crB9wX@rpKn!?j1Hn4b@yv@J0+DW)dlFYtFF z+a@^z&D&F)IM?4_5oMrc~+=DB;hRHUup!2Rm1ckY&&{U8-1 ziR&_N5uRPywNybeoQlE(;gXJxLjbYwj^ zb}uyZ@Y0FlnhBbHsfyy9=CWBg5_hu2)~%TGxJA5BAKL3R>cjq%KxXco*5yLOw;k=jTa{CYyNx%&1toAzq*D{GW0lK| zPDg;%PQ$2DL~(<{JK(aezSAGl=dPfS+~Hl*%#40nsOCs?Na_&|Kk$kjA!ym-_j9we7Tyg6)#L!`koj)kxw8_Ap2x2Kcqv~G^=Iw znRGAOX>bIoh$G!VnS|>EkJjDdlVbC;ypZGZPMn$}&&@22@;!M_Ttwa}#op!fJnEcb zQz-O=en>^kJRKu66R{taog{8^$6Xy%TQ6q;LU2oP1E7_+&P(O-)ZB_a2+3~l#Ct?Q zmQL)|Ay6iTV;^hPox3UqLf9vKLrNDg;F9Bv_~A>YS~~eHXTaW*)8>3Y$yxbiSiJJS zQv#q6FC;k+s=3#GjFz*0b+ITX_TCPLRyB+QDo~cVI=3nE9YP^5b5(9G3~_=NOmBhd zGJCu)&UZY}1CoMF@8Ho8jOLr+0xQ&Ix}=FCxudZj)XB2qyS&k&)6jE(X{Tl6PWF|Q zJ!`b6rE^HoUS6kA@P`WfPM~6&^qVI2cU=yD2-7l z1cPH(9D=!K5xS0`aT;8JW3^!!F&70!;2Qu`(lUIV;yBN{HsLXl^>Q2Ya-%no;>FX)s|`GTN`pJlTT=sUBHe9;?@~Rb;_sIp z9GmUaS7P_DZA{(?*HR~I< z&+yv(oV^SFulQ$eo}WtV49Z-QS``JIxih_MksGH}w)Gbp+4Ma>K@N#B+?ZcT1BH|K zAZe2v&;!5~g_UkuXI!T}tp4(8361?5HojZ_^qp*U4jqja;hB?W9JNGw(l zz+U0|kA%Cc-J)5Q9KYi;Hj~+7NN#d)g&kJg#5B~Zc5g%cy9oxnvFK7TXFz$ zIbS*9$Vz{PEN^FchE*LQxg5<9b=H$xz%xM;q}PvZUQj@Djf}%k{Mmj^=Cm~Pc;tJ< z_B$hUaL#-2qd{0Li??H zDXI-x`+lAl9Qj7SSL~o4s-q{%27k#Kk5%2>d}!UWZHxy$aMc>jPgmW4LiI)_B&8E& z5RapuVAzV~Y_QKDhwqGj3-7TKIC9Of=6vbTXd*uBoIB)`I_kh>< z+nkv^nWB9oN|lvg>1KsONjmxq^!sULC|WGEqJY;?=4^KBJVP66Mf5n>(Pfg-={xtX zWuUN{en_*&+^Jaiw=UB9h)4ZFt)z=%v%x(%Y-(4-mo|;CLv<+mmEyVZt{ekG3pIx=X zsa~ct<6UROO8I~eihB&dV~usg7yGnSYGe|L6{Kxa4mFjWvt8W0Vc2k)x;PXdOY+w2 z^5G+E`m4S;_0j4^ZfWacn(GcUIs~ASY_ZmY5matiuhLM?f+b~2#eeE3(TS8Q?)Lst zuyjs@lX(g>S;vGJCA*GLgJ}xu5e-R5;pwja8t?`n4wtWUJttLrB=u11j07|kUUTxE zH}1t0dfJ@iQOJ>{5YIeRFcWf;Oy@sR4Y^ZJmFm*rH(m?(FF^UJ8Jd&h^an6yJIi6w ziG5%wfDpg*X-TOfKlXNF{ESoC6t4%TcGA!g?3Sg1)0~KU3N%}_%!66GnW&|@Ll(r7 z9U)Mt^^-?-Jd1GL*e3ZQBsPrGY?DDu6G}m?Xq1}yaGjmo#vrHq2n^1yKWvR;aol~T zO9v3MzhhO*LeN;a|22pt+Y#i{DJPN0s*1E5V3Mc| z5W6ch)d`<+{BP8SQhBf^wYlt7!}8k(%VQ^I3cF4DJ(i6KJYHcKmGVQ%^%vR6uoH0k zKXSbUf$K$nfIaJeh~deLF*wl?AXeA_dOKMWq*o_GuG6NeVx|U`3skPVTY> zi#)2Hk*3Oo)G(*?SmHXs-#^;lnk%2P`LOWMq8t6%JdYamm$J2-P?bX)zLPo8*h;gC zuwx^Y0QY|2O}*Od7tG6Q?j(`u!~wxHHJk(UL3B>PpV$%w*u6YjyfhSc7QI7w{x{lC zfzOSy6Z;qzsOr~?Xu9Ngz@~dY5LmFZhmTr0P*&yPatQg9;?tCYubhGL5fly}tJcauHoqp57rt61cm}MPf`zQqCR{dwN{fR!)E~_egqc zKdUlt^#?Q1KznTbx&COh)I_Bx-YEs%HNc>nZ3eD*}~Y9`p_?gd(jpIIn8v zYbcy9K`OL|?2RRwO+xUJ1$*oH1!WdMd~3aY;ic*)2PnuxP$q3hT&H&>+7;rEYtp9` zYK-)T_xAt+gYp|X4H$l&dRZUPOI{Kw1n0;a0R|RS70&Dt&b^;vx4Z>qF#uM}pV7O0 zYm}oloaampYYEj8 zwB^{mKu4fM-I#%9Mi`|&55SGBNOOW7`1x#5J|7Q(i+H!*f7Fy&Pd_-g?CW%FUs z+#;Wpq8ZJfn&gv}UupqpZtFhHmln-Vrl0>tk)JZ&wdc_?Llm!UkqemfL?6#eDYWnR zwnZ0AUY+}$w~rvQ;pYV|T-<4)cxAWzla9hKxkriT*^M2bNghsj1~e5ozzU2hNy+b6 zmA!1!T>WHmggLA;<+TbI+NtysvUVul#{Z@zphE616Ckaa5YmG9Tgu&7YPM54rq*|- zwc?e%%Yv~3)pb_mm`T4o)zZ^Wc{DxT4fz~9oRSl7Hm;r#*a{bE7@-C|akN}X&kr$zt zdrWz~dVsu7d5wDcpa6h%%kC9m4fxgM7h=B*=GS`pFaB8^+ zzqmku3;W=!0e+|bB7GwQ!=eI1LjaDUdjgmLwkO8VH!3t@PhezdkbDf+_k@P*iM3acSq$=kave=INgz!*L~Jv}=W#?2^Nu$yBW*28>SF6%B zs5{IKjW}Ol-?f1KGxm?X%sH!{Y3L;UblUW6^ZH$U2ykfdQZIXQv^J3k>CiVql9%nP zDP=3wI?#UvbD_KJ%`fK9TD{2c-D7xdl)iEOo^TU-Mk#u4qmWD{fB3%GcW3p@Qw{(3 z%C%&}jnQIF_oL^oYJFs_PDn?y_Ub#L8A{zt=b$fckDn`s#yL zfVrG2`cedpvDZT6D5o5xv+$fr36`pWv>-#CVET0J&GS5!Y)CVZ1{v!>ubmC*KVQcU z1l4lhzm#}f`Wjbhh;isrf0`6Ht=^LqDSNTtD&$>nA7+u}=o zA#ibA6pa!XR?PM&Oza$IQob^O(({dAaNdzK_fZwklT%JAb7M*uqq@QI&ZBQ5)2ZOo zsuwN;M(Q=Y6rpUl8NPr`HH4I z4KTxC@V>u9!BkG;LoSg3DfG4gJu^yzz7#Xpd?)NfM-D<_`Qo={8)@|yNIrY#DcKGC zp^t&GG*`0U4bh^D*>%^26C%7qKM#U&^{XnleC2xg3bzb_%nuP+ z9~!wZ7^R>CF{rMUwDGF7>Ex~(&Xt*aSMS7ciLS_7{Gq3(C*m~We!RgG2sKbJ&H7pO zo1>}`HFS?L^x(9xw^`4%SRn6uuFQ2vbJZ8k-IoiiNZ0=t3)VKg0v=2q>k`9a? z(sc(E1}m+K??c4vUAsCLKG><)ELgpcIy|5Z*xMtn^5LpOP78pCEka{I52lB0MTCdX zu1=KGnKzku>|JWi_EPd+4qK+QORNY#Do`Vof-qI^o^K5cE0M`9(G0xxm=0#;`=T(MjCXhs)1U$nL9`Y{DhzN28i-e0*( zM%wTEf^%yYsiPfA7F6!csuioCu03Ym)!h5!Gx?@3lTbw>y0nRKXeBttM*J+#QpFgM zTUr?V;xXQfy~&I1_|o+vB8q~*KunVcYH*Ij>q2>UyoSZv81I7PtjUiQ3=Sh;!7mz@ zGRiiXVt(25y^TcM%z0{C?(DGVI;Zbwkvg|%$!jJ-9Vtro`CCOQaSO-dc;B$}schw- z1_GhB1U11oS&n{AFP23tC)`}xBO4<{ORM|0amOqyPUbQvUj~2ne_H`NKWtibp+M_u zWX4d2I6uEcr@vo*SwH0PJ^M#bvFh`#15b@)~h?}E5yhoC9q=Br&_nO_a=I&!eN%#!lwej08$K5z^NUeKi-DN4sYJCsS z#LRx~rkmnK)Y(iaq_#aP;Xp{g_=|@usIJ^B^WCW9%IS#~=R?I?Fbj#M`B%@*ciQlJ zLl9O1-woUdrm^w^m%Qc=p|gW|SJG37azr!tZ`B16{S`gWEXhX4f z`{3*ha0njp-+qjv@l2Xhwi; z{9(+hqmbu*a$#Y?(`D#U5viKPbps?NgdnaHT4iq5)SL8h=kWojTpU-B=Vlzq$LLA^bm~51cSjUia|>wX+us0L;|dglOcJ_%Eu1I-~#q literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/model_jahit/gamis.png b/TA_android/assets/images/model_jahit/gamis.png new file mode 100644 index 0000000000000000000000000000000000000000..ffbd911fccb12cde852d8f90df5574d1ba15caf5 GIT binary patch literal 4937 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 TnLM-000000NkvXXu0mjf!!I8# literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/model_jahit/kemeja.png b/TA_android/assets/images/model_jahit/kemeja.png new file mode 100644 index 0000000000000000000000000000000000000000..86e57fce87742497500d18953328bed514695e24 GIT binary patch literal 4962 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 literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/no_location.png b/TA_android/assets/images/no_location.png new file mode 100644 index 0000000000000000000000000000000000000000..0286cbdc60332880f2af177f7c288c6f9a4b29a7 GIT binary patch literal 27399 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

^! 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 literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/payment/bni.png b/TA_android/assets/images/payment/bni.png new file mode 100644 index 0000000000000000000000000000000000000000..6542adf01ac8f7f10a8576408622c76539843d01 GIT binary patch literal 49369 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 z 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 literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/payment/mastercard.png b/TA_android/assets/images/payment/mastercard.png new file mode 100644 index 0000000000000000000000000000000000000000..489d836229efa9c2d2f4afaee99fec960698717c GIT binary patch literal 20512 zcmeEuWmj8W)GZFhTihv7+$ow+ytuoU;_d`@FYX%Lid%7~xU{%KaEiOb4bS`D|8PIt z4;hS+oVE8_bIvvQIyo6cC@Dx{pc13Pz`$TgONpz%z`z0DUMNV=cdoGK$@J{U`@Z3ezxqFxKg+|yz~pi^O~XS|QsWLphJm4v-GII~LhTL% z<9~rd4*eMT|KI-qnEXE|h|=Gm4_7@I#-{4TmEYfF7Udxv9wTt! zUi_$Y>SC_9lN~)e_N_0Ru}?|$3YoXwe-{vra!1{J$k8B7nUCoGo`s*Ga8{OO=5UT- zMkOJ#;xR-=rA7&j7S|%82MD=5CTLBum#55rp@V^W!tDvl=x6GMxOnVK6+fAQT30gX z*?&2M#9E9sGtOsY8Wsq2Cu^t%4rd%Z**|VtW%~YEW%cP|Dws9sFs<*X(lEE1Cn>V6 zhqDZGXzRp7cn`xDxFG^W4Zn!wx%lR5W;0k7wa_}A9*@_OKJeJWV#@cS$*|tdW>|5K zH$rE$b@^a0_K;y14_rmybKFw8n;u43$g@ z5g7P&($4p=_HQD-X$>&1^(^g7#I2`*rLkzDTr1SRo&D>k?!@5v*-bMMNn)+s)8@iu zbZO&D)2cv+Wq}^V(H`WW)}M-CM2r!v98a5HWNFr%o2Ttt8h}D3uo{&@i&C({78Tbx z@?fI^)rDZ>U_BEvEC{E;LGd^`Le$yLRXB zVc?Fz=ePUc`OfNjX@*-YvZTY~b+4AktSFFpcURAnjR25VL9UKnlt^QtA^tajYm7RR zbLWLSeYZz3Lzd`u(qiPIFXH=YwRYv(X5&s>`=RS~PKVlZp8+a}fZJ!npPKn71ZL?W zx~wUW8fL$Lv5h6Wzk$s-p;!QQ2t5}6K2abuz%w{a zRhTR(6;}qY>yztvrLR1@nYSE{-%N$CQ=@D}FptZ|lbGLN-+XxW#2=dVRH|BQpLD8J z*lp`2tGU(OBBE3i=oE3Jg45X6li2QWicC#$sY$)wr2+WD8QbL?3N#)65S_>56V#2S zEjTdinKN*jClNH(-F1tP|K2rCUAD1MFPt;^kM`(OzlmVcZzIjj9)8a)yV1sNu2j^X zc@{?Go*+XF{C~I}#`hb4I#iK}+cvkt-#-bg55}HcDqOE~Qw<8a`~h}IOiRp(nJP?b z!0%J(Oi7%)Zrs*Z?_Ndj?EG@^%v}=3Kdzt?0y|XJq*S#Tdmf5VwCG^zR1}%9;%9i3 zOkd{hQn{a9%3Zn`ukMnJQux|P-8K3(ID3+25kCe;=M8gtEyxNLtR?nHzC7hu`<<3R zrMq^pxEaMt^}DN{P9?1NbpCPVLfdA)3LxphMJ*g8v&Vjk_bO_`nm+6EAYVRFBY zjt?iDEOhLwUKtu}uIbax*_^68DIVo@(XlVUl{JRB14kuplk=vs_$=M8hpk^mlKEYV zn4Isps22XLN$1oH25pq7_s0K%y!srh)&0fNBbn4Blk~oO8Jp%+(plpF^}G{b>-xGn=}X%UU0U#nOK3T)RkE^Z-qN{y^&nvH3Mrd{KoqclW#fR^ zb!8Q#bbpV>l|w<%YA<8Rdg+gYXV7qDW6g4QecHirUX4R%89im->RD{K@xI9GY_|thG22cx|=l<)}u1_)AYW?^@i_$X+d9p-45gwPBpxk~g zXRx8RXH26(t)dxW)_J!$OXbUl67z@mUD{`}XBH>TZ993B83Kann?KMA5UH3XWBzDH zlkfiHyK&VV*pLhc+~rL>=RIHp858Q1p-09$Q|bYX+S_3VPtwwzwnU;%d_v$i+p}6} zV{w@&nJ`Jzj4)mkN$0_s-8iSG1mnG%dzTAtW$PBM&PN@5@lW%{KM^hTiZH-dojMFv%cF}d0t%(p0sM@fhEO}!?bv@La$N> ze)7$82g?4Zi<9j5E>Fkk>;7NF63i4w@uicmgm(S}tV6*RBwS8RRA!*S;)~f2CF=N| zBji}rcGPYv@sacU9bUxglzOE1aP|9hS99aeLV*Fy-Kzd zUYaH%w=3*+u9&;aP~^RK>mu)e@D?%qS!R{n9+voCVAft-My)tbE@*bUeFJW2M%ejY zTrA9W*}H&po`pPh=5Tvv7p>6)>3k8X(AK;QuUe0m`DHoPK3-ye!fR+d8V;^qeEvWi zOG2wxWnVe&+j83>J@DA~_3{GG3XX{3MluB>ZNtjp90Lm8I)itaJwOo0mq}F7Pp$1`t5R<{E zBEu20dRwT5(((`&&LfX!rd!=N4NJGTpfG+p=`p%&I$+Z=>o26883}CyA@Q?**vqrO zU#zksgp^rMpufw?ANu)M z?7Gsq`pn?`_9Jx4=$yXXczq9?m?~iU@+3Q)9CVVZ+_!VZF0Af|h!HjsP0sOJ4?->vrayR|gRs~#u#YgX1fw(*H|MoxveYG^s=#JR-KFCAcg z;VKF^xi3+|Kq03~3SnjLbovu0b<%345DN!|nngloPZVP7yJ@~P56=M^9VLJSmAtEG z(o_-|H?_%5{d8NYb$Z<49xP?i+k09}dB5m_jg5eZYe__4VJTUHmrPzG`5PZ};OG)Fl8ecRnh%GH z%R-r(>mTV47m1E9s$P^Jqn^;T!YloUeA$hmw7u1XcYQLz`NK=;B_d;){mBRb&0jUi zJLm#g^TpQaV%X`TZwBcLqcx8@3{=HFl>S}8b8nNm_P^~xFnq)7ELnH@*((Xj8dd=c7r%@Pn^GuvnJaM@UByx8%%g1k7mb|cs*UgApD+v}6v601H{96FMs z#)=*NJiAxdXVbDGV`SRMM(k!dFsN3gy8!)2UvCK4Ps+JD;PMYOX$L);0GgYUmkv)j zBJ6i%);z>Rd$(X7&*B|>CV~iz=ps^vniDq+PpI1@=>wP%<`Ez@;UeqkS;;ijWlL_FxGN&ecT_}Fy zvBUxFZ5?LU@`QnaMLmzzjux|-8x7-zm`G3(x-Ai*_M*dZa}PslKWJ@R-+yH!~$%*be+5h zJd?Eb&Wb`sV$tp)O>#;ie@*ZaToSnhTd`#OLpeOY=hsTcgh&Bk4ORJLNwPAeWZZy9 z0kQN-?*F6>J0E(^KFvR&osz;R#QWgm>1ip*Q13Nm&!;As$2AmXT^W38wk6YJ>-@e# zdK_qux}73+&P9s>jTJF$y@)?su;lXCgK>yVFfSg7$ud8WQ89PwrcunlBJ`1ApMtL{ zsm}JSFL`~UDmw1p))qYR_-ICn3r-BKgU?s}@H_9DR{jyf$}M^Mc7}K+;}EGox8R2F zz<_Q^oHCh`fP7n)lBWVO>ZCNg%z7J%DYAI+9m{-5_UWgRCJRA)&LG05+r1b%>Bgj( zc{!>iaAIJub6^Eon^`Dp8vFk;Qo%^*Hl{wUB}CU4cfX3t8HSs9EO`J6;`%iPmP+VP z!c?WD19PrSsxC$bP0-4FNq@yu7O{Y+SHF-Dpfq)jxr41~U$CIfReHYvPMUI%|}v{yYua{DL>j zBHsxJ;#u;p{M(2!Pn#1=(ix6v^|RfV{0SCYNKh5^gMT6;0WcpZ@S{E4q1_i)Q7gV! zMp-1)UU%8C&5iq@i@Hd#^~KPkYrCi*L4z4(e3W27$0)O15vxs1z^xP6;t&W!jssDSv|)Oh7jm3h+wy19f?d7F$h8iCv2y z*0ec^P$wtD1z(Pw|8_lr{MPtkvNnb4Gumyr_U0~;im)xin56Az(vH?QY_V5ZJZ@7u zUCyX%pLS)YP-Q&!hSl7QUJ;B}i(BF|%@nuabiX#&xGe-210ZQ8q{crOA*S!~egybu z>u%V|VLe{$^rc!D&)>d4YWfN7;9wRomHg)469)N=}j*lksSdbC}_b_wZj{pGIbq zFiH0qqTcJ`(Rzu0Ii-iWHuI^^tGw!2(VPW4hth)0ChdX+gdz8SEwfwIUgH94p<)8U zQf2jSp=xp4eUJ*F-SM*GI}NNwK_@8lrM%Abei#WPt}j^kQRnj)6A98v?wvSZXF@sA zT`vmeZ%N0k_=5d>5r^+L$(gm-KE&grCiwCxdn)uSQ#I#wLUz|Ze=MD*M7Dhyf>PDZ z1n61$bvZXw=|?;WK=xOC+6$JpExwG2|4S1q|L;bIlZ1C5TbB~S`1iiYQt#sFCM ziw5o&y|15lBs5gZ&oSXP5I%iVF?f|Z5*C2f5yAM);~DW_EQr-ifp%hRW!G}~sd3UL z=!0UtrvjiHP0_o@S@GW?Pxb^fOB|Z}yTPvIH zN4oEwM&EbsWrvhh_;A-hBUe{}9p~}doniPs{Si!32bmNl7A_Y0s!5wo5123!lEdFl z&nsjeWS;fVUhw**gYXUN>dy$xmVd$;lkdINxTc|e;aUM9>zh?M^q5mi6hz;<^e4RH z{VG_g|I3s_`XB6?w)@aPFZH}!m-9y^K*k^d#UCdj3~l!Y<09rGf_!=Lf*pmjB=aTw zt#PB|#rQbrOZ82MpYUecZ-AoMXlt*r-KwMP)d9i7*#zuH@Qepw*cCuLcU%}Ex4lR~ zQ}2pX=aaSscguC#`A5=@%k$St#U$yPHnENy9{K7%Ho4o5-WmtAS57tLWvDBbrAxNM z(;I2!ZhrFxll6bA0(*zK-A^=0W7zCw7kxBUg~VIirCpPvh1SgD1{d;7G3FD9mx>I&Y_JUe6BJBxwcNZL}>*7hk* z+cN2rRTb zd2Q$&*XEfHgo_|+1o%CqTSl&Y)!8@+_bI4|u zaNgA)d!b2J(HMEXRngA%uY7wwpZryCB1NakKe2W(7{1@@jTuQ)a;DrgjY@RZVl0dB z&+P>;g(3Iz2fS9A=sI%XZrU~NEE*Tc-_)x1<&_sp=eJ(-FJty?&8eI8gLrb!Tm{mfg!9WZ1+9TO3sk?M#^ zLc@UUVeS|h7t+lN5D<7+;MzNfN(e#PbX$nGAAmFz!TTpx%;XmdA$xZM&ZfYk~_AM$rM6wd>bou;-!KW4_?HjH&4*vu+C^vS|@2}6!W8mWO2j;v6 z7>`*gM0FsU=-3MVDL@zp-vr4n>6T;q44G`x;2zOvPYTW6=j=fB)R@{2kppc1#_ZD=u zI^o-iAuE591l3@yl6~eE^|bZ35qhg(H$^+Kae8o!PWv$ml=9%@2dUNiG1TDKkpe=8 zp_7V~_l-Jf{_2z@xuhj_qZD=FPncF#K37$8qCAns5&9P41C?bv|BsMfzH7ALB+}J* zC-&AYTJp#^a;&)H-}G4FJrDbn1xX6?V6n(k>NV|ueXAjZzepsD*ZD)<_9*-cYW?Oi zXscrFu~z<(I7*ou8{Sy%mzxkMY-;DhvAupKtQ;-&e14ouOXAPun*)0vQxmQ_GK`1E z*=;8r_p|^hkq-Mj3X&C60f`mIo7p=iEiGr;GkSiH(Qn#<-0fpl#W|F3w*VXXWjqRP$o(!Gq5PSJ30)k(jr%c3$z7OqZjK)(=|=Mj z>a)IU+6tk%Xt8=+m$AH;m~U3u0?6iQ-Ex!Z6d4$F%&#(7Q-+zMYBBzCZ0OeJJfYpbP5`WMK{|1hxu}%e&j@`9>v20KZ4x|+-iN+gGGmfl% zMA4B0tv&!;VY+15C;dq}-9CI*YIg#*CeqK|zQ1BUOZbu2a*D zo~$_ctT5ZCA@)D#Cxkk`t;DSnQ)^Aak5r*5d0epfnl#MRz{7q3M?|k`n!DC-fUJIV z@fqRaI_TJO4yJ2h9#;3SM9EU4$%2Q8tX4bv_iyJ)G5U?Ss}3ik|M#~5sAV{gtrl?QGcYcUA!+R_}i0|4^8y9a_Pmx!qUf&2c$06;;OOb;YBJ!{Y~BLFL1!#GdA473}= z@WD=NFUqq1h?jt(fQiq*l&f{mev#bX0~nng-tR3)wd;4mN0Gi^pHh&33~T(vr#4&W z3&sxq?$cq_K4td-b#gd-+|TLrDLRb8S=I+?755St1C{x3Z#(S9`8NyAJS}c)j|g*I z)Ap6w#RqG(mv|iUqh^;uU%^0keS+VKb#L zJcK3u$6rnGD-wiL85@mh**$*6^E2vX#Glj(VF>KUPp9L(hoyC^xcy#p>fjP{Ju7d z8R#Z)2E<1_M@flenx zqROtl@>Z0@H#-;aWu%+#+nt}ZzT$)LE~^c?0r37f4cq&eF$MvrLoed1{3&;y4@?aVXNq=%r5)8S;t@6Bd#2z`uS4(M{6zMxLBae#d1VnIkSbo3#+ z=Rc@neT9t#AaQWm7=Q)=ZFl#Elgi7`py3N+K zJ5#koN_du{eRQGU3A{NQJ@AZco7(X^bRWVtD?_2OLK4(T#ahf4d(avYOctdVOTwk& z=E!R;=+sDMc8{!k{SuIxzL>p;RxxU8ib0<$fh`*am+!9}|5JU2j<(;5`)t9Y@we5? zRRpcFX#U)wnsf!r`4U}5zt-c-Txs+KUytZ2h2dxFZQy1ode0}zB+zCo{@(I5#y?mvIvnVjL2%sulKZ{eI+t!;}3 zAPFx7l3)_sy8GgjiYq!q)3m6<1dkjV2==i7Z=Ls0#EZ|Gm)mNy5UCJ(NonADNrT~4 zKapU4Ky+L=E-x;v-E$n=CrIzzs_;S{)uv4N8+m|9nsvblMLwqO{yt)b=q5q|;^A}5 zcY+Snn9IAk@;(={6t@Z|ZgAY*o@(-#Qr>oV;zN3`>isp7q@y`ZDPjjA4mls+_*Hl- zS-u+(Korbyt57J8hC2Brc~6skI2$$>|H|yiDGYW=M+5@v*xt#auamz+bVB-<9vHJ6 zfTKgH>>!FJtHZ9e#F|;tK~{KvQ*k&IDz_Q)KDu|y)LCl+E?#Zm#E*}rTi7B573zFj zZm)Lv#P$Awub)w4+d7~~iF4LuAqM3Fktb*199JsY#5W5ypq=lf3uxhjnSr}G?fynj zhCD4o4mus+p{mZ7I@}$Du3m3>N&i--KaLJNVFvWb7EP|#H{s4ZJ_w)~{CS@>6oc0DEzIkq(SH%TP)Db_FxHJUFOu)V4a{DBz* zbzj5#+eSQmSZINi2{PX!;E*h_P_c%#cA8>0z`9={`m+}HOH;jMaFjNTkPi@YCw47u zIYbe1wkA_P5YkJpYOSP$Boy7`UKiw_O5LvT7w(Io#jeA9G{qKRFaS=NCHG92yCFX) z6DyGK1bj^oG^h>UVaAp&s`(5XRKnkEC!7m*)tb7vK!kecI~?-T&|OF?tjCHIE5vUL z>%97GRgdTnP0^4Xiry4EB;e;a5wu_@CTb~d4pv|X|Njjt&O7s0a`Q#dp3Btp19zPr zE&hPYxr~Mu$nFjmjRrp;in+7e`=vK=yyy+3kKlt4 z{B`~~OpBDlLGegYRd9Ooxar+WW~2on`Dgq&|Ba|Ftc+B)Y2aR})*B2>NXb1Hl{lqA zn0}I>_OQyx+E${FA80=zuLyIDP+|Zn5bA%#)Iu=aa9g(1pR*l+jhQRGN_^H6Cqq2iMFG~&MhcyPrzUc z{3e6>ml1G)iDI&+n)OyE)PYurV0uG$m`imW4!)UFOPTB$e}Py^K^KOpi9H07lR>#3 za@ICqKMDy`k%rxOZxwpUtQws$_eHAmM zA(v6iVbxzLqvt`NBBHk-W*>TBJ3@I3+P!-v2|PsFRz6VfanhhL4~0g>_x*xaghB$< zpqAZYm)ReXFs1EKf8`2MzOwt$GW%O-7&6jmdG4{l+)vXd{1bGj*Yqv(IzXdz9ZF2A zE8@){5eMw-tm!N7VXUa9Bi<=?6<_I`pujX@Gg}{|jFZ9t3pSV7q9&rW(P@Rp0sCgm z*+!AnPaAaAM!x|N7(MFA1wt()u%jiW7=|&LCYH3@oWM>8rF#66wtnvA`T;-|PRr^* zO79z8;m9>04gJItCoOw!uMf4?bPij22>4OiT^QG#t+V@^Kk2KiQIf*KIU-fMB`(*R;5Pp--i|P_TDBSr0{et+cTRTqjQ`l8}F^}_J_*h9Tv7i+Ol)DAEZolTc|x6)eacKC7+r#^O-p_ zFdx04J)ws&LQQFm>SJ8tpxkWV-S;Mi50t&<&;V$c=BV=HG=N2lot^^3m&3+cv!Uy6Vqo^%Il;DW4CS(1LV#30EVLim4DAIC&H={|Zhx^M2?A-2k*4(kva>Ils zTjO3B-_b|qtQG-46`$3@C6ALP;d~demq?hCbIl1gHuhvYT=F~j9)!5i!xat~D^Xd{ zQwpH(%U>oSPE7w7XiJ|c+`Z=P#K6AaUPwFfmt&kwp%%O*2F3VLX}Z&|HtRI<5UhYZ z7~UW(JNhiN@T;UbQFx~L0O75GKZD>~p_d=y*~U5hc;xv`n?L-1wbnfK;Ist61pltb zTWpi(TylUHy`!&&$AKnym_|~Dmr0LLUN<3dZ3<0y;N+K*`v&zxPCXAMFDXL$OdKmN zIEW)Ao3!jz3dX3^g^qr4c90C7s(*rRc-o;)BupCua4;#?t%uK~UAQ)+8X^zp0?gZ?NEp7JYx$o(qE z)4n~~Mt<=uz=5O)#e24NE4x!dN0wp$WunYy0{XuXaG;oHiC<@Nrj@m3 za?5H4Ev<=fw2tV0c$Os!_W4=6=azfsFZU4q!{Ev=a)tkfV6}Hk_GPw6@gDkn&=fB6dH?j&|A>hBv?T4<$Lwz+Ap&cW+;a?3LoTuJ2!5Q*$z744;6;WFN=F_ zx zGhRu{zIlkYUD1Z=Re2D?1vfhapkpIv*%(AHiS&UP6a!!OqgSk_Zmy1m{6N2E-|DUA zG8=jCn*R81%St|nN0)qUcL9MR6Vk^fp=(2#6@JV@15_++^D%u$7nD3gaEVWi$34BA z$7c5p@l#IEn~=n!zdV0DK}S~Q4GBw#m`^k`sA;`B+nR1JfC(xoK&TzQT1e>@yXFzAC@lvB4G03~@uU^DmKF5>w znlG!V|0U4e!v<8X>$%2&LnN8D!q zySF;La5)yCa-MMq04OAAw{@H_ej#h+rE7*Qj`q>=&P}YY4 zvCqBad?J%#-1mAQWJMV&UA@HOs|xZHLZzaYgNcYY<)~ezW$TOvxeEK8>rM^v}B-y;d%>?>TSv^Wxbo5bA$r()=soH4{k;Vg|(1WO2i3zK74^OPD95vmcb*>64%I`&i}$)7y*| z`QM7!Sd2uq|30Fs$i50YoHVPZmTm4E1{lnXQ+D?r{`8{@+;x9C*&o3Y2d4^tP?@U% zA#ZbO+U8ryG=WUC-=y9g& z<(IQx4t$!9`0ZYf-=M*k^SG$yQT7}lKcTOoXrq&MaY}&R49g>c)HTSQ|M{Lye7Qi4 zoxD3rYWv{lIbvGm=VwRtwpS9*XCNsK zGH6~x(SG=I>Q6xq1QQM$DfaWfM_VrL?A9Lu)F%;!Oj=^Bat*p;@MN2sw z6YqKchJ?BJs7`O)`hX^f_x#=tO2Q-Z#K^-SRb8JI|a;izKh1 z07;f1R^XSdLY$OO6Aw=WGOsr_1aD|;Yw{|8cL`{~jVbf{_w>4*T!k;UAk4hA?RD}| z@E#Quql0be?!7Zceark4J^Lz9x7PK99VTp~vh<~>@~zM4YgH%A!~fTGF$6u!iG2om zo1JH5NKvtriyciL21id11ntk&-$+whSr8sBco-ry*p2x>qEIceX1P#`?xbB(p|#l+ z-cjiVgi@x%{`&Q>e`|uZ>nfA_4aSeR>nt-)ZcVTCQ2=Rl1X*okorn)wqj2eC44Oc( zXlja`31!(@24H9B7!DKb`Yg}A(Az-Ovu3RV8UI{FyVqP0t~p^EzN_`-npEz@t-eQ% znhtxVjeL0IQ=z}UWZ&-re3LqkGP?f5|H)cDX`ea4s+TOy8c|l8GTUQ`nm3V?=Pg1D z4=lVn#ipn4d1p?S?APMN3`J3Fho9Kg&?;}&15n$bj;1vN2Z?edc+s)WB>rKpI8X(h zsN@x2_VZVd2cJe*a2;3R{u!7`2BKO|B?%DA>KZZKnugOFF`${Crqo3pthWR|ly`VL zG6TgA2Gr9_$aPvl6NtQylCUUZFUhoZ0+EGH-z=G!73OG8U6@S+^mZ*{SHwrWe*gwc zK7pa)odCZa&*X=c;GKAx2>h2`3-OMDRnhJ}pr!#24tldA=!)V&n^GrCYy8x!uCqJ? zXm<9__^#{jt*~{W+ok9GuSGM9WjV9C4~F#T2Cu<^3N&I0xxf!t-A@v>b*L-J{ zH~a^(UhmW$`H~yE+zH5Y1iZJ6j<*zv%fB?IEy+@drF@WqZTH9$j#0r)l zLmKo-h0H~NqATG{)pMEa3ic6k-!mu)*ZNb|v4uS3)r}xC;+iC@3nQ4|h_m6nuU1-u zhSDSsk6(E{pInRe6pv@h<*f5NE8xVY3w=s|l3ojO!w+8BapC;-vZB>W`H`B>a`2o# z#+y7V``L0(xU~1Ia?g8czpvh6FE?+BfIJ=g9Mg0>ZH9hy1jE+STx3W;h6)ok7CEqU z%V$a1J91j4o7@sXX{(v6P|oI>XTA11EG92I2%j1FO7$1-PguNWZPlYCw|o1zh2{y;V*vj zE;DJ{-g$|9soswgI#ajpCUyi)_ANv{!w8iAPr~}Yxh~{*OzfB&BELTkVy1oiuP@3u%P{R1>mAz-cIWITp2I(bk zKD@uphGho&^;hZg6*O&4HL}?}#(oh2po^X`zAV9H{lyg3dUs5})&pS-RF8&%xW5x0 z5l4v+-d+{+KbyBSKgYkbdZk8pUaxud15Z@XzZAM(YET~Yp|p&8Gh@S{g90!rwjXVW zx$43XKarK?XCvgH_PH*7M*ghsHZ=i}uQ_`n0(b4c&Vs*qH0qotpvv)uz~6r^k?M9~ zM}ccyMf|E?rjhi@HYWnS1psoXcQ(PKE`he}HuT4&Yba=w)ZeT^Z7zjg z7tuVTH#PoD1je-;y(%U9b`;s?XqK7TMIbUdxS^G*`I)J;)Nn7YZY+%*LmvLh0DkcH z_FjfBgkEbPd3RP?`P$^TENNpqrCt}~hflz^(&HS{lSA0gH^O-X69<0Nf|8^Stiw)Q{BSLPp5$i#Cin(nAd%*FJNu@2U^K=iMpG`!v{OjTuEgRI=JhK_=bJqdSjJLC8GSw1UVJc#4LJEuvl`8K-lJ#5fH#fg2s>< z*K9=YQL$AH-ItRYxD)jwS^?|H)6Y)i$HeKzn(k0)vhP$q9U*$e8o+DR*APR+oZ25r zQ|ar-CmP!!N^XEcUUuKS5u^;pM*O)5c0P7@hgW(mX)J_s$pf2_$%E3l$6VxFcpH|t z>**4BFr@^3Z~A3pyXJ^;N5%EoLO`{0)@F%62?k9O@gpRUg3vy@C7EK@w9S3X4Eq>} zlB|A^bo~rPt4G~aw8L1!%sPNPOAx*JJ-rHZ?>nmX=lVUO*Vb}Nb7fR!Al|T{AI-){ z9#1iAS(^=V%xn=Ea$X&ye%4vs`=_PdfS)lT2H3;uZiO%oZu5Uf{gn`zR!Nw4zA;*e z{rWqRPow3|NIYrCd$dfb|M|6xSZ%VnY(M5Ms_ zkb$keuS2TghSzX;g8{hM=wTM-%EZh-a5sBPYmxJZ=I{q=$7$v5!^jDeZsq-fI(`vv+p{a>{HRu{q zwrlS3=MydU_s5=g@7eUrzXGsCO-&!AF%TEkyW6|M|^!AFO$@>T*goFV=U$7uiO6v5Ee-W*JX-GUh=Xf0l@sCbA3l|2wiPS% z_%z2=*RA7FzE1zljU9&X9O!E*h~s^A`HY2NPHzws=k&gpzgdA~FD`DbKG)@){I;cg z$T=(Kmyc#T8*GLY?5;#frmvgjgO>l5=O|e0Ba$0Ik6>GP&~tdr2UCF$FI-2#r@cZA z$3ValyoWkWQ4%rcn%F}OcI$6HlYbelOTN3k z#trZv)$of99eq^ro^gIl1;6PW9Q-4Pwcr1saj?2S*z)8{eowDX9 zT0?#AYf#7_0ef6EF~_&kKlPWi&Rra`wqXi0d1UYMBqcsuwfR0~gm~}8aOv~PYMJLO z#?%v89}}d~{h0_=@}LTq(mT4qqXFLI&C8=51NXa(Am<1gT=TpzE@XM#MluXU3-h#NBMyHymSx`9zld4#2+@hz4u_YL)s`2Fu*{It=_ypT#71-_~$4F=DsE4 z#zN+%wii|l+)r(^i2l>{`1xDfBi1to;SKFFCkq(J@6hb?`lqQd@H9ve8z;}HXI7@O z`!_Q&Y{jnZlJ=iIXuXa!6}w+wr`y~jB^Bj4uPGiQU68xTg0e!SuRl2=bP=HG$u0#X3+14IwZe4Nw0QN2iH^`>J^!{+}$c> zrYMRAk6^7c`fx3OTVU#r(}i-}g|v>F9L)ZTjZ_%LadYykpA$6Po_{5wZz(A{^1CU# zxzf+iQlQMxoGhs-Q_lda0?^~CwHRpYWZC|_F?5h{uko!#kVn+CKg6|VsL|_Df;8!< z4Vq@WOmjs#e_5v4R2t9kdi-%lgBnh-8%-gp-f_*NF9mD%V58LytJ(^sJhHLPQ_P>e zek2C-TlDjx;J*o4%xZsHuph+4DKZ8JE9K3jqEkdY@V&MjwcL~BssVY~LM$SHAlIi_BPfOH=6CX?fimKy_(?IXajWg#J%)-&K8=A3bLfBn&t~#-dw-A_9T+Y zl<#$$Z)8&v1_dTu1+fILye0A8p(&bfR14+n0?UKkb_?$|8}7N7-wql{(axYBrLXmd zyMZBkqeFOAnIUST*eAL?-}Tsj`C3)n{l2>2jILxU+ZK+L z8o|N`%LKo>63W#T*z>nLN&1yiq+P9L#w?X`L?sI#xKQwRxukf~FlGLh`8jTWiXkui z|Fm=N-%L1e99Jq-S|yR&a-@AxQ(vshW~7T$E{&N>O5bF&xqQNRbC)h8hh^qccml)9#w~l za4T~1MD!&+uYc-&ecU8HO+}47|Ks$pQb&I?BtDSVi4Q#87nYFkeM>E14r>KHylC5~ zN{MY5`??bRT3N>7+Y$#^$gnQlvwEWv2!k|Wn!657=Hl3xHmgjKh>%N>4C7aVq^a%C z-{Lc^^OVIe1hrTwDk7gKgJF6W1brfFhURZo($E`|bCoNZY5T6!-hu*(LR>-|ri1Z+ zuh%cF^3$wRYFNrCHxv5r(Jq&cn1n_HZB!%EV|3CLCtiQc`$7Wx@D21pnBoB5j}X=#^l?6G+Y6L!2EnN@2TLMx*hu%) z?Axs>eQ__w`RYCjmwDD>TbIm3f5KM^Vgwxz*aZ4qMK9CI-|3q#1nUMFndNyW1=QRM ze3!AKn9LB^RX5sbEz}@GPHDy&4RMrEY>DZ`vva3r=vGUEQ@K&(y@ zZg@TkKa()>oT&|oX%eXmVLELeFPt#lQq?tuD|cOxwkC91Cve~xTj^=eik5{h$AoPa10q~!9g6Cg|1n&ey6#`aFc`hehUd4WV>CRsq}L27u{28 z1qCdEWqlq}+(d#Q7d?!DIWF$7X#Ljoy4&!aM}EK_mC2D&2cl-Z`wQYwl0IM8W#s}Q zf9+q{b|NK*^~=U>RRDx`s&lK&VR%5~q2AcHwFMjq`6E*h(?|J0Q3y3Y1#6GgS~FK; z|MnCAI2~?sg}$)nUp;#{UcYlZL9Luy8~@UBQ(1rJY@sz$n#uIm%lxSfi%!I!1Ul`C zA_jQ6*H_2*ZDDQEa~ydsHPrrQv&edCy-;3rVN<6XPb|$UHUQKc=TVeGEl$A-A`VTV z5#{(iH~3u*yR3GW6)f7IgU%yg5p109CDl1xh2|KO(9TMcWMf4G3USHLO~=csXjVb2 zteFCc{ptNgj~}Fs>gH<=C{E9z7`aA*un9VRj7!kxt7KJmD=oUpU|l6y=3i*3@-qMi z{5jggy0~Ops-;$5T`9cqbAW!|{S$XUJ9=1`amd}|>jw?i+J{$1!byn*(NE6qX$P{o zyT?>q*jEp;+~D4UcC;juHH2~7N}>U)CWG2s&VVJz?#rQT?^i!&FHq?>nE8*(cl_QX zgGhdvCfA}1&P$1SyqbtodhMd8HO~8V$ex1p87G`zRSPUzzONb_ydVFy%75W0*7EzK zvQbCS5Pbq<`MyE!{DC-ltfXw24CL(an{pRI~oo+Txe>3iXmB+(!W58KtLm>o|RM)*F(P`J6OWMF8jgcP15>o zXRYnnLGKt2eH>KONf`ex)%1*rJ0nJSoXAGADplpASBB${?TiAPFgX-}`Tn{Vb!;h` z_rB@O9xeT3rUXU)@XjMXNuW7$ePE}u@L9t(@cCPqW+bF!LP39+Y2<6KqADMj_rGmVu7w5oTr#XZINcvjRX7lrW)eeomBvERWxpmKRidmN8qN@C zRcBJ&M2w|h;$FjNM-w#9*{d~{P=@a@Dh3c~G=6e2LS z>mg|D3lfOaT8k5(lZ(YPJtOuuGMY9Bptd>;8_vfKPTlmmd=~?*jP3{9mL`izvwHZEL+~wHF>$5NA$K?+c zaqz76zd&Xgf)1Z#5ZgcU#6@Vur=RC5mTkDL0EFQx^EDyL+}*$Al&YZfW@`_%(J2_J zpup(0*6+!X4AD4I-_he6U~1@6r*Gg^ale)n!UkeJ<#qvX`{oV&@WvM~+!8N|cF*A6 z77sO{XOb7|2##UW_oq^%;!i;j3J2>q5TRVFNDW`wo$avf!BGvJW&C#OMj3Z#SrfH1 zea^W;&$#5b3JBHL-kZ{|zD08zJGQ*_Ye$p(Jm&REYF6K$Wp+gHMx|*Gc+_GsB|k74 zEF6O)=Ys80-8n})OR4D2ZllW9Z@F9_E{m2k?x&3HTk+Fi^;dG1Ivgp!i(Vj23)-8+ z?h@ouu4zQ=-i+{6EcfT*Hy?KazIdt{;O^X180J*S3ymvQg8=1xq>;9*gh0$^2-EsS zb}3RJUiG>#aBbC#{<#+{8Y=-3oy&bvq!eev)%3z~T&^r~orP3>YxmdC5Iwy7p3$#W ze9fG=ToIYPgn2zbAZf#ku#fW4a>nF4NUK@K+zyPw0g zx)JAykJgp6S;%kQn3t2AP|}e*4r`K^dj<-Tdpy4jAa^iRW|`Kk0+X{0ky)iF+W(XE g4}$+sfmErh5xyL5*b*!A*ORlkYImi~%Ja$p0CI)AtkQ$m11r;S6x<^0|knTo0q&sFn zQgUdd&pkfR`@QS@bN)Zy(zQfo$sPON``XvO_MQ)_%5oHBH_0FfqJTertPVjJn()8R zlYsB=I`2w=KQ1^v)pdp-@@x3t1W;VU4G3a{;Ex|_x+kpuARqw$1sQglw|*YK%D-R# zEbz|)|19v&0{<-V&jSA}@XrGOEbz|)|19v&0{<-V&jSBfTL3xsh6pbPK#XT2PgJ%3 z{rYEte-`*>fqxeGXMukf_-BEC7Wij@e-`*>fqxeGXMukf_`kveY^w)K|1%5l|8b$` zILX=XxjogPetu`pmVwW|`JeZfkEM+Zx{eTPDQ&UVJQr|7!Ok)84u@%Q`@-Z{Oo=S_ zmFI#_%&vw%ydnK&#qt`)-Ad!r-K*CLu6*X?s8M`yw&H8Dhixjk=xCX%A&DF5WdA{$ zEN&vceP+B^`G2*@^6zs0Eb#v`3xvJ=0sB8kp3D1^x*|{K>1J)ER5cOFQS4Bx2tTi; z`#wi7D8-!Z8cK}{MLomOXZJaPL*1O3)Pm)1P|gE0wS=e7oWFmA$M#wm2tB*=;-cEX zx@x~YVlfcmR%4()Fn4lx9luA|(T(>+|J@Az?CU@un&KUzM6|D_Vyu!lV4bPZ-g5b> zx#8E|2W^!dgYX|>ci$=(WSWI(J^k_~jSSu{ob@uISfk$!4pSVbZZB0=UqLXk2>!} zE5tOC42o7?7u`(I|GT8uhu5P2y%e<7)|aWvIx%bH6UV$lN4#QdNlH4#RM;!Wbc;oo z0Zv~H+n#&^&t~<4z0L3VsT~tgCUf3Fr1g2Te(0xXIQsMWb^ciY?^(ml{+^XbjVFMB zT2Q(l$+#;NK!Ea8kQZgAt};Yn)q9J!;H+35YYly>hLyrU zyO(#OMMI1tEsPBJ+77a-8~-k%dhdT1iP}kgHX`sDe)|d)1-a$Bc$a5kB=VfQ_A<&7 zcGN}`{ddUs)P%r zB5R4g@qXRZ1y7wh|K&lAH{2||8|#oB%dmg~!|elh+(oFOz5zXWEMqnXPv4l5arCLq zMhfRMxA|HHopQyTWEH^cj5bHxy0B`H>NDfp69MWK9f9sI<1L__NN{j2QeEVT+fJ};skK(o`XKJD1 zc`~*!V=3F1)i^BxNcWMC> zgDXxWuv~o}ToKRT?IizO-B2*o#WvnsNvZC+`#!{+XAV`O@hp2{QD0isN0C z9o2f_h?n+BYxJMFOb1M~dzg(`xP7~-2&5;LjJGwl9`)H2Zm9HEhnr?rHMLVs%lJ!* zUh@8?c9^JS-nvpnjN$N(3U$L0N|Id}O*mF4-`~@WE4Uzd73^Q5WO!t7QlVJ6ZG!p5Hh2+V-j2u|KDpa8>P?_5Q_o4cA31_yua1o!$`- zR5M|(OOw}h-@B!1@??aS#O1C8FWH_4JXu7DA@%YfLeVfE9~MLEN9EkKrrGjchG}R& z5pt;s!@ixFtR*uy4^qPVTG0n5-cD;-O35Wpt>PONSt+6l)+j1iA8$IsfoIg;Hesav za|0u0S5bJUuT4e}^7tayVXfNgiXnA1K-8vftNdAikLfJMolWfD6vKGz2Jdt4tP`n< z`@3W!h&%bmZE`!ml)g4>IrJi$sEs^z<*L>Zt4d@5xlZ1g z_#?I73yJ5v?-ZG_`t-m+lwKeLHvXM7=~;jvf>v{|Yo*0282e5*N?B~-ml`bEZspWL zKc|sLN2SW@1A-3Ope5wCZUUDBE|bIB6!!}grqFRSTxO=NiqQH?8vxC%LFA_MB_;EQ z2h;)1U2*T;p`V)Cl7}&Ouq0CdR1Qy>$X4GLj$8K2MJMatIX;RP==N%bU4~AzExM|i z_^bHU%SV5DdhSC!7X1ZS3MkA0tSR|qDrny$mK@D^Yx4ADkF?CsPqRoi_0VT=CNleG zB}P|Z?Ub~p3ZlBL@K#}r7)e;_-QKu(5|4PyTfpJSd;Nf!GS7=0vi{QN`k}*~m7Qe3 zgFjgHdo48!ErZ}|@m`6i#t};&zl>={X8ARyCAX&}v+{eM2FuCWZBw38^$t<);vBo_ zX}~z}IM(NhX)yrLr|)!>jh>a_89}u^#Apl>o%dTW`#PK7Kj!Ofalm`WA}$t$tX3XQ zGnX8~xbD`tawlCeIW4lLv{>>$eJX;|| zs-uTSMpLZ1)Gtc)#C6lLSc!T`&fvJ4f$+mb#Cd3roMZ+W+IzpkM}FFn21)3qdZaW@ zS~4a0+)SpqoIO1>xu!%=UMWt{tO`McJl4`Gntm)mKZ7AC4#|h9nTCQKa`U6m;~(Ia zKhrzV7rzgGDIKyTP?B5iZMCJSD{4$ZVa4@U8LI^8Y4M+fJtSi{H=p`0Kg6fgJ5V6I zeMu~T;3Hp}ip?Id=Z!246-21aw(AdF|C_)LEAB3j;wf zzjy&`wUMCqTdHXZx*v)W_;tipdi$PaqOyo5f}l;xGFE};(hW8A&zZ{ROCg>;Rm_X$ zUh!Y|U^>U6Ek+MO>5s{^1UHeyD|hHp>4hJulj7JQ`@>EbrL;eBLbk#VSy{1Vy{7tM zZI64L^sd)qza>=XYgk)X_YHb0-IFv!Z#1RGx&G999XXQsY{I5XRsxrF+_gC(wV?zyIY`C7UT?4CYXoVp-lO-H?jmz>55pJS zIt4S|fp6Wx$8!?EpscEhB-77^-va};sRjeWC!o_PxS@sHtMiqj$}PcKnTIs~b`RNT zdEA{_JnTG(H$MC&bTyU(kA(!imDCZq+vt+FmqT{#!4VtCNT$C-zz^k?DULs zcu<9?T6?GC=3eI9I%kjLhODpU*{|)cuS|G`#5&FHobA{XgdJtI3?=8GGXTyEU-maL z;ts+n&OmK)f#AZuFS(+soi4u(}m{fT}ja%b*Z z7~hP2zxhI$4lLbJS>wWUt?Mf=HfG*jh(l2Zmb0cd^b12%iGi(;?WedgXDE80e^gzN zUMK7S%6%aHCFtwBYC0$N^D?9BZ>q2CR3Zpfxk(fg5UMG<(Qz&|cAJcF{?j)ECR4X; z`ad&;)EPx)89(p8MI2vbH{3S$^fkjh>CZRs`Pzqagsck`k=N)Wg{g$tT|cEQ*2qAN z4EaoyqY5HvxK$6w=B&6Ri-~T@a_{ZlH{%YR`}Ty$;e4k>UzqW@V{bH@-+V1GmIrd` z>CIl=vsH}v9;vyEAuRUqs^W~JG!XLn$%_j!(1^@R=3UamQKDJ-nKWv=hlv${H6IOG zy)g8sT5DHhdfUmG$a&XEnNal>_CjHXVxLOXaL6C}##hpt-@a$ovBa#07bhdgr>E1u zmN4UXLcn_ik{QOTGAU5dKPX;nJJwxvROVM#XuH(?7I6(SSI|i4{YXdpv*yqEIQgUL zl@sVx&LYeAQJAGWK<+s#SSG_$ZZ0KD^TZh?xd;MXS_Vf{<>JodBVU9#uWFsuI&!J( znGXCgC9NAP0R@c*ne1JY^>k|guI9HFLeMLQkK(dkO)hfg8huE_QiaFIeb5?^$~ICE z$~kirQ#zZQ*5of*4Bu(S|6Uhef?U=5~co7>}M4z zB-vn#I^nnyz`&dIz$pN65xIIp)NMWU6_qbzW;8IG-F*M}=XdUMkhCPo&(=h#>{E4T z&q=>0IyxRH(P+Aj-YfTO_JV`J9o46!X&5d`eLE!F&Ohxws-wmWLK7<%(g?he zM0l*-kgOs+;7knR9JzR;7j~+fU_r_Pe`QWu{lIy!3QG@#t=#A!7_VO?O}C5T@sa5l ziBOiCjh{#sD&CIUJehDf{u!pcA{H%c0Ag0EGJ5T4($F@a)bV;5J3V5km^5#5onV^X zo-+Det?3)W>uIDlbWU1>gZJJaEw#~E=6SF~2g@4@$=RbA`&L=%hR5w88|$F9ph~m; zv!yh?PETlp0|Y-d*CIRK7mY5e)<+s#wGcGu7x>T7-V=@MiP85QPs?-&pj?)8aLXd! zPpUMITu0rz(aI~7OL~PLM>-%UBb$i6SPA3At+^VrODFv$p$Q8ZqI&pw8jyZ-<`P-s zzS;{aPF&vHZRF7|0RYG8|H9+d-lpR7_ke?$ zMw!dp>b*lvGB}w0Isf-f0ho-UBoPPn@bDv`{1Q46ZrBg6@()mzo@G!4hcIloiU8Uo zAbKTD=`sEKE(K~m+$9+xyZwV5zGxlSNm1XYttE1|CVj8@857KCf30Sfef{D^_v1@ma&yIKrWs4lEtzz??e(wNE7H6xUI+W*kx{M( zg=5E=h4v-Zvy5ihH&{v?|YTJuNr$tc zF(2N*a$$uI%|{no3ECcfEZx)F&&VOwnsOOPoB#}_I5&KthaE7)>L>lDSRU!p*qv~T z5@x=g^)?HThAdDd05*6wT0kJZsb)qR2$~#E-oEgWEq3fN9D{dsp>qSe3b$_`d4(BS6#+RNq4YgTVM-KM zyxIQ>({}>1o5S5lCOAIJD3M_0$*i(^adv-1X=)xrgx>vbRI{{A_WHRfRodkgS}aAy z_nyH@r!`eSfUC0puXwNj2|E>1(PHI}OBb#DX}$(5ix#qwCuG-nEv}}eAvN}M{aU91 zlDhrv&jJ*nl}MF(Mv5>8{BgJ>n3gU8ajH1%*i`GtHT<26o}Z${I|^2;2NX2%JaKsM zIGoiekIqoUgmb9+>5ADl@qrRU_h1k8nyeZvos|C`)bM#EpK_$c z$lQv!KcT2T419ygrlLfw681w7=a4EoiCJ~yiu-`0c(7WRr-|Wl(*oe;0e50Z9goD_ zB{(7Z|UYIfwNG#Xv%h$jPLfCmGQ70{Vxn5;}Iu2-zwG3o87wr ziQeeCw^cDM%HI5Wk$5XW_qY;4G@au#IT`NXkV7Vx7{CPueW0EAh4faHuwNIw*63KD zL{?~4LkBUA$YKegLYBl3oXV7e$getis@;2;zAVKdzg$q3n4bR? za4GN?gf4%3S>Q71TzSXfWFK{d;{B3Ks{xJ?{Wg{o(DXHsb~zp|xp>F#$iSr{xF?-k zU4?u)MU-xh+hBS_SgQ^k&!LqP`e%ckU*M8<_%c@*j^hyINbn$w>T2J7H(FAeOFiV~ zszGYp3S9e?Dgs=!R9hnVRPkejROc!KaP)eO%XBkH1MLU3r*oHAE)-M~kLuHte200r z#a}(EAwq`!cy|#!O~drAo&-jI;|#1{%|P-U~+S&4Nvzz{J;`Oljl6s@ak5^ok!;!yE0EYa9cAqIzo)i zmLIF>An#(lDD&vMC)@%Aoa9ID89PqMn-K8yJNyu1q?ik>M`39fRtHU?Z} z7(9LSdxB}rddQK(YPW>~dRF%rCf}{g?{C->)x~qjN%6?7S~OCf~_Q4 zpt)^acy@)DDwEE>{Kyb~ja8}oWG|i)hBluN;e_R$O(KK#$Gyr3IJj#%$|82hP8RZ5 zDe$LoP@FN~BvXGsMmcho;wVy^L?DS7Umd;k7dEjw=~L^i>zEk;e1UP~T!8CGhFb?o z052}l8b-GX1|+{Aw93|wHS82JP&q%)jxQzcUePiGQ?3Dw?rj`oLxlr^-%{An3 zZ{0#>*79I=B}cyknduEmNYcN3l#+A~y`1}XD#9fWL8{8})5U#$E+FAH&}abXN7ilc z=3#};8fKWEsPGGb%&jeY z))9rxV9VuckZcbag$tM{+nC;HIC}~ygnoSO%edmd`V3wN00n8#G|mnsFSqF94hJj- zEPYR73bs3zwdq~E97J{vYhjJzJV*(V^4Y`nP;ak(Mf@|Qd+uJzkpEH!*wD)#J3s#x z_*Kk)j{MgT8npTH=!=@G2uDSzIa|AG%Dv^<=}@&y_b-w{Jl9zX@mbVHeaCQ<)dsEA zWZCK|0!inZGE&yxKJT`sv_C1ewcJYL?RU`kPP}M6pFR2|u6Ce`OxpKB!Nk_9GqIC} zQ@~dAy78%i_%0=0oDc!2n1y1i8`5hcTvY!&f~RLd+c|o9{ue2Vatlx(akDkIV!t66 zVLfTqi-nL&{jmVdzK}89Tn8m+MbLE>Xir|ur&S(K1Mh!X=3}9F7KCt+NaKK{2#Qv?y-t$>p6y*pq@hw49rsruFxa%0Te^-RR2V(AH*qj0978%`4m=(8XXgrKJB7!^0CH6)j5z@ybL4nxm@uOJU znN?WtxWAAf{Te+1RPmnT6;znM7ZP9gG>+S5OJ`uI=$(t9&%}L0o!i4qef4h)AV2mi zitlv3=SB*SR1w!_ym!5jXRd~HTMLn|TcrPN73hwCVN;TsFe#F+3-r{sSVav{Y!xv? z_8KpoJwRt!u5-lt`~Wv5VH$OW_kheOo%>wo7E*h&%jGckW3Gq$=o_4O>BzCryVE~8 z^hZMOA_Q$bZ(unqd(-qIireeZ#wN+98sWJ-*djUy4LLbmk&OEg2~fnB{>3 zKEUBA@VBg3FP$fQq~Z80bAM0-V2m^!!IxtBj-dbpxc$feDo-CrFO#CRFo>0$6;>a3 zq2uD3h%&7~!Rg_1L!DhXNk|r97$vUoa0OMnh9Q_vl`Y_*A+lC@lJTuao<|S5JCZL;U+S-rgK09?6Tp77OE?N(M~gi6evx1 z!ELq+fkAZ7;TU$BCe9q^dZuztdz6%})8aUxS`wGh(N`^oBa?Gr+u64Y)#OO+jsE!1 zPu^p&J9W=4vuk{o5{(W@KoMig|7R9pNNRWIhgN3A_L~3?6#m|;w#!!?+#6wp9F`|7 z-BQy1!N4^?Klqd9w+}&nZ-CbQa(!68ZZ|_AV>sz}@@R;j=DXM`R-|-ybOv*-z9&rC z)*j%=Mjb`MJwNmxHzu;rHi3vowM)sK3ykpVct3wOZNTZ&-M+LK4j3fewHLlhWQ#!9 zlP2(*oga^516eVKHRVq>N(@lTW;R-W@m6BwrRR*4$oQ4q_*&azrAvwu7T$)@V_c!M zyYc&nwWY8|En)PiCStUAz802SGgw7bKlL%*thDjV<(jF%;)7Oz_-ut2L7+?BF_XFF zBtKtHECWdGF$|7)|H~Azwg7n$nc7j{e0a_#0X+4mM^yMe7efPp`UJ-=9>hp!+}3Ds zrH~xM)@tP!^5NCx!BxyT^xDPW8(0yLw2yhn$tp*y2-}3iYs+Q|xZJ!DbBXo%6jR@> zITz$2mZdzTLe8{Zn8sY=453AvfOCgDdT$@03DOc3>wqKf9MmQRzS(vcpWHgK(%?Q<8+~>`A;=-Bc#c9@EQNGIhv2&lp!$U&?+m}3 z9wqkvK?|Ld07~J6eQA8wa*3~eq0hI(A=!PB4@>{2>SdS30_Gg!Q6OO4aX^E%`Te`H zAAJwBklIQ`tpgD;Kt!tL3G!(%CvHvna&Nd&tU5s>*(&8i7Dq@7WWENl0{- zMqvF$goJ?47T7MU9}FAK;ZG#InzEP**|o3&TE^Q59pJOBzBf{%JvLw zsjG{i)i+=0M=m7_acSXkCi@M$_<&YF4PYDGwx8nTZ*PXQ>0Ge5@m}Wi9?49v8(#Pc z4c|=WdH-A#Y9mPBpaG=j21T{g>1!0e$Y5-Di2zx(S^#3y0kSumad7g_^qUNoKbxt7~$TdPNp~0%$tKaGnXkwxdbADC-A4Q6kWfk}hNEc?C`9#oQoJRb?~w z!xb$WocyUD%MN7NO{U8-8vlG(2uL_ymS*xqX+iuvxOUBY3hIr*PmI-3p(>(w>Fc@u#Aj}0Ojh2)T2QBTTX#m zQ8g?b<8;JO=d#w=$e`=&J(Zj*u~R`oL2nB7cSSzqpypCeI=_|_8sL7O%z5KIdjjZ~k51?3jiPSgz`_#^1gR{$ zfA{uJ`CFL%wJ{p=%Gq0WQv+Bdnq_6zIr!JP>@~8{2q%?4)f*vz=wmR?LCKJ5XTd?_&E$T zjSIlHZ;*9>Z%M1Ub4$2x7sul&{uIjUxOtm4Z_sukTx>V&2{$%5ufp`t;!Gz*EB2*hLQ*##pY=12?yWUH3;=YqoWOd=7OaQKfWjb6M3J9CUx z2D19b{(smuU`0?EIo`;cQ4)^YjY?(M2TKA{N2bjx*ar*iB4r3r|DT)oThT5&p#shr zbMbqu-zW1oz{+;~OGkO)uUaT^A>Nj>-CytcHGRH+`Q7)M0Q}0bgc_3~SG5adX&@)P zFlrAGkY++mOB)F)GFb!#onDhdKr2C-3VA77E_WfO98J4cgATRcWlT+CUsfTmBF|o# z91Nf0pY=l*FVNTvd76Y9tC(=afG>M6(*kE1(~z+5E{ILvAcZGygQxVaUSTzVhrW;h8|jtiTFo%`fnRW$rWtVV-3Z{iml#>_x+L z)ozivgxGNGQ@juyv#kfhIN6VSKw7&Z>U|kZ8!Og$2CR%WqDT$35^Yd_2JI zOh93lSj`31)8XsW`)pW8oCN#G&vo^(t+o{!2PxzaQFO4Y{JIzxZ0I7xKJ2R6dmcy0 z82{+}rJ}nprgT$0!VpBg>IF+eIFh+M{1M8BJdZWgJOA#;%K^}=_{(KG6cE)^u3xQk zW0(cx7mL50%BwY=fjXZTT`HC02YUq~)up@09IS+N!Ef!-R4|Od;i44VuZ9{2tW|gL zd)T+#5RUUqpz-L@bmM)aQReM47n~?<-8VG8^o6|G&jG8wwCMeFSc|F!p*lTaarKIo z1_6}>@Dg-Dy3c%W)tOC$ikMWb)1P3_vS~KC)!T7cJTZwkrHdsfX{q9f6)cmA#$hRp zF(g1+<*~TJu2Hav=hl|5wjEd~@ZPvuBl`AlMs910W5n_hc`(IL?At?-gSR!1e(@v# z>w5T>9p;Ca-xR4WoR=n81nvFhn*~&$Y**ZfB3e_d~#s&+pj0O}|5k!CK2xrPq;=sNrAoy{YNO#WH5`EXmZmk!ls0GxbL zJYLh^NpR=qLYLz_jD-h^P-39eh4zBs4!Q2DK^TB~_c`t^IelT_^@I*)(Y|Jj4AbD{ zlH3VMpd*&i5r>mu`i$Y@^4Zm)MtkFuA^|>AB=@rB_#avTCMLvHO)!Es&Z1cCg@6>i zpa>EW=(*nm4$Gqh)DkTLF9Y=tfZ&)+5r1&bl%^{{!$I=hQ@rzIOcQDb<2q1VkjcoT z`xFn?>B≻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

J&>c_n8c+Nim@c4r%`=*0B+K#>$j2_hkv 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 Cv8vMm literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/payment_new/amex.png b/TA_android/assets/images/payment_new/amex.png new file mode 100644 index 0000000000000000000000000000000000000000..50dfd2ad3795f49ac4030303984e240a51016f4c GIT binary patch literal 19320 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 M(aoW9yZ_lg0i62NzyJUM literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/payment_new/bca.png b/TA_android/assets/images/payment_new/bca.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7be79c3457009c8d5cd191eacbbc974e8ab8dd GIT binary patch literal 95653 zcmeFX^;^?#`#%nXfP#c5f^>^CNS6}AsQCivhS8nUpi)YYt|2-=y1ScE)6or*qjTig zXTI+H{rw-l$8kS@;n8ukyqr##?25%vir0!3jzoB6-j_tLWXz~tuPYGdzY&E)0hX3g~G-8(@X9HNXh zRp6)^?~uCgix)${;Ss=w77m^jB_E|4rP>cgJUl#NJR*Tt0s^A=;J2^qCEmaIjdMRe zJu4qKugRb~gDVPt9|zd{)Q*;SCI$zG2?wC~=DlzB-lAV6)HaCm`tYtrSZqZvh-1M!a{G8PLt9<4KH=#_7i&Fsx(&XeC<_Y zcmG36OZfSRW24QqodOeU?T@E#=T(HaygJ}Xa@X0vRS1lz?XR;l;DyDz`{Rq=n->h; za>f1~=-c22SiArC{Lcgb^T7W+@IMdy&jbJS!2dk(|054{GV4;A;B=m%Y%xd_34g}= z!9bcvHwqB30VpU@h!BDTRr`ZPf?mwl^BO=>q!%5o^@W@qi|VYM_h=l{GS1ZX z%104#5F6CxtHKaRUd-~%1^@LcT&x#D4|8zv#m`KyhHcl=SFMq11BE1<91^ltagv9IBoqsWJSDef+FGGr5k$K#ku@)zHutP+-4N1(nIPK#j&&10gQU zBl~(mK~*8||KhS@evf=5;6s;4g{FOlDx)UAbpSeHH9iO6I)_4YvH>#eH1&l%>@<#> zt9{bF+iTK;DrTyO3aY#SZUF4#JJvF28rc6RQ-@UY)?Lj2fWU0`v~lK-#1qObBeea2 z4nPgyVbERRKC-Nk^pu>G_TY(gvx$zLV{`PpT;S0u@dYPO(#E`u8N@SWZ3|Ls0KW6` zpUusjWE($g7b{yznK~SKcc4;s!LhamV1PR{i`CT2&2u{XS};E_ZkjO_uQBvbk%UZHyL6Jjv8vq5ww!cbO&G{J-E7-+SBk?BF@McJ zM#Wvy-3~E zmC|Kw{XgjV`lvs@xOOcDyQEb7)eK#^u-ww^c=3DKaRML|L4zN0mG zagRR5m8~|N0!3YT?XA_XdGh1!gF?WZNu?Z3oK~`FnY7xw&VCN?oTmM)Tw`_g-@}jo zP=8+@MgJk|Dah1`YCKvW)l z?gpKJlAIc4ag5gu2(5RqEsxYLr!zM|(>M{fWYEneX$jfv`HE^!{J;A1s^Q$rn!1S_ zD<2PLv6dDN^0iMLDjAPRLfG2or;cy6hzoUeF5U=#B$Q^%-|TEnj14V~1?(&qZM4^- z?EG7VtvaNVuHT{HvRDLKgYrc1u%~u@c!NE)uc@P&+u9?T<9w9HJLi`e$-G zueHA9ugyVYQqw0J-FneRTb_=blns6mX8cA=?_$0GLe^(+_&)a3(9cA#SClT)I5%2<1oPx)XJ&e8 z???cAtnKIB0g#O8yzr++8b$D0#LJ#r8R>aUY;yiQqQDHe+rYkYS9;JP+knoQr!wLD ztD!O#E>Y_*Q_Qd}^w8InW8)Laa0LL#Sy(sCzV^GQr#_h()}P=ZKH@}TvpSwuETu(#CQRP*yS|4TKbuJ_1&^Y)srx3qWW!NE2WSO)YCa7Z29Um4Vy zGO{gO?iVeXC`>~B0JO-lH&`F;bikYs+g!TB|Hi)?_2baa54-2n!Dbxj7`EkH!{ubr zgQ0pWQ&Cqdk@2yIclxw>gV&mgl7Klwp{zyl(w#t2N3J_+gY9B-le>2G?;$Hd4V-%+ z;M0)fpCrm{yu1~|AmnZGNpY>at*V5icQu1=Omz9<`g$RN7Fcu_=_gbd%nq9t&RGOQ zD%kh07Xtg}qxmSY2Zfd?;M`k=`RQSrCRPiz=Onn2w6*8IaH&awgWs)Kqzw?ewwY)d zm_bD2mVKK153Jy}fEypoDCB158jhA2NS{CXBjp>Z0EM+$X})?Vq=JSo3dx%W3x zR6~YpO~JZT@G9BeY_jXEt-^MS0_j~P_}XCrlp7ulOp#P$oJPz|Yk36Oths{hPcj0L z2${rpf9cbW9G6JBJi4Oog-nI!u#wg*9sXMUF$HJrgO%nn#%E8 zmz-nb!i^bvPFpRrOhe${t3r^LDFmXeeFBD(ayfJ5mx36+(PgRoKvS7z6jbL^Q#X>^ z!Oh9GhvE|3K1_@h$)C#vToe@#amM?J>xbPB!9Slxz{H|4NDJ z5|r3DOS85X7bzOZPhrl_PR`3sG&O^0#RF;0GS^2YV91O;6~yM@vaHRW>A`Nia~P|# zxk@#~3Om5D1mMTw+{$WoWsH&w(r8C5Rq)ix{`E5{4K7h+Zc>G~WZ}NQmBSMFtid+D zRm9rkol!}Tcj`a`?Q>Hh#^`sb{1gMB`LrnpY~@6p+S#B}NgOe*F0DJK(M1`Du-ytj z1yw&ahYmIcKYMT*G`0|=FDVMsQZ>*NGGMe!vTc}>q?5yg*Bxi*FEfKPN2VaE*RD2u zxuc-lK!%nZ?xwY83}$v2e^qLIfzL$8V0uFq2dmd>Wlh?c=0tx#LmFvEu4za1wA4*@ z@s`-sK(rv5)tROYFg7yl)Vi4QNW{&vq+qkup&&o=MlLer>$C4_TT0ctdhk(bHe?nd z0lVBGIj@6N%5d=mXn+8?AaWLxnKA);)ABYhA?IB_hc!6H5l}&9^D`HSB{%!!ocekx zv-X|cXg&(8R-w-#aKg&=V=i)1lT1;N+PesnVX35GhX?>5mp=HJ*Rb2W-D2;WI%RDR zGmW9oG}8wFj}QHK`a6551+U3MDxH^EzskvSa!kjDJ!B+G){1B%YP2G?5d-7kR?(jI znX4N|tF*yYSx3+h`i1L*%G8_j{($l8GT7zs1+R@mo@V*KzG)Y`M_&K!qHO&U|IO^k zj+C%E9{@RzxB)F~*p@^x5H?gv+Sw?(!b)Y*!2#ffECY;J>Rg&o2{3;;Qkx;*l^7ab zNTn}s^m~kqA!i9Vf^z1x_V!Uv9lprFVAL$yVneS(vol~?Ifsu8$mAjCG*U6$iCSXS zxezTByPx>lUUO;P@?e?X?dJF4zZH9>g%iiZappWvO{nNuq54v)XgjaBIA1;;!G4)2 z0eG5C2HUM5F4*^vp|XjhEv#0uiGUW_mSyy;(|(e5$?R2yk4<$wcOAyuVKHSXUIPZe z0+e3?B~d$l=0ajB7qbMx0%PB%Gj$nzmcOi#8!W2OAvkSzJgbyOh?U=&tB%vX>9bTP zmj<|51)W?cyW2*jWXdkiNy!W)fP(at4*`eEDme=ova(=<8xMyAm{uFJ*<}+yPxE`< z`gj+3xhvXNRYI8E)+W7`5B7y-o?F{PUX_<{&hFg(cVGMKAz@Din{flMoVwYKL-ko7 z$&Fkle+JFpT32cC;Pp(P>4(u0VH*BX5OP2(GOe(7jTE22=zw;U){`LO>iz^9&4o;Y zsSD6itZ;o3x|n0&GCZocP&H$?+H&3w@X5KIBk6HO3_k!YC1{zYL4<`2f|Z66@IG$z zSDy1a%a9;txMtI27ji}0nA>hI7LGhS>bL(bU%sNaL|Hv!WTpxE`O#X}DO^oVJy4gn zdP&+-shxhjnwTJwwnM=F2W!z_9`BPc3+A?j%AqD5{w_P~@B&h~j489M_2dbEbwrw$ zs)T@@3~cHuhS7<2p%g%ybY|awvRi~+%c!IE7~g34Pw<7Z=HP_&&0fLbBd8Qc4Q{!F zbwVMMEhktLgLOLNfV(=3vIrYT6+yyfL40jX+3xTGk5kO~wq6xZhL_Z15{0y1`goN3D|Ac^4gpUpiQPMh`9~h3f_3R_`&s_ znQ%BcNXcEMI??i}bK6>jqY*;}G!c4GKK39{GqU>i(%f?sW-fpukiAKU#&yi_=6u1U z&y~0N??4pF`UNLUVe6Lc&Nt$^rifb(EX0rmI#JIm87&==(X77v?3y287sYIhY1IVITDdcN3ifY0tapckG(G@1}NMTYZl9|J<0h_kb5 zF|LaOjSz0@TQ?swznkwRfAdLv;lXQP3iLz*@iJ;NIpq{Fy_BS7mSpk5e%$FgI-PcT z<-j>pc29!~Xk*;M&W@4bt^uwKAGQblX79E*{BDMZjc~Za5$nnbELrxijSuV>DdfP( zXH}&Xr+N~alhySu@=^Tx8nT&nby=rwH3gOequ>v5<3VyiOChwV6((Kt%%-Rd24$R+rV-#IZiWRux#*DKX?tNDm z!mogd=2BZun~Tdm{614!BQtcXo3<$u=SWsC1ur-UvY(@3O2oDbE*6@$Uw+(byqwds zk(|%4@Nm)M*F-*pZe{b7k=T!)3xJ~cNV$4i+w{1A(5<|fnq47!j6!?h21eh@9xD;Y z2phqNi{XrcCPV8L`LSsQqyvSd-lxH|Eo}L0ZD)P~CC5de%Zeg&!+1e1+@-9{d{|-^ zZ(yT0C0dBo6^N9}NUqV|jhm1yZKxjJG>#{&Zx_vHTk{fW3zn$6D~YLD9*Rv{uKQ1d z)??!~M3Nu9tGrg9m3MnmuR&?pW zmZ*OnYF_JUOrhJ1HkolgnJi4880(|S5d6gySoYniUj$X z=njXBmZb&z|IYv0YdZPdBZqVl%bkUAZrBQu@T(1>{En(Jd;*fM`nn|nHjV)JKHyFb z49st+SdSQPuit+7@xJ8Y&a{mdwsCI~x4u2)YGO;;*kA)>S$o1C8JI2mXBDIkAm$E0 z*J@3xiybZ7Lw|u2<;Epio+Z26O_8p;-aNY=gQ6#ST;-UZon_8uc)AAq)#I^k93{;> z9&&scI9IU|!QD~0y%VZ&@X2v01&k4~ZWL!9U<(@fC}KTc>Iv6Ll4PR+BX^vO&~nyO zvKd)?m^LN7zi%2VGl*VaqQ+V_`K`en;0eYt5VH4dcGKahwu2T2z$mNWydr<&`t0s_ z!RxBS$jiP{_pJSg=W3B$nid}bR$lAj!=c6vuZ7J)EmUa06CgT9wYfuROzv0%!*yEI z4f^Jp$#blj&hOYnulJO@Y^bi@$EX}iX%DN3O?R#cxw=joA^Kf8&Kt)2;rXBsK4z#4 zB|Snq4!+ByEUmdK7-9@``voK|m6Xzq{Iv3!KK&_zQEfEHAPen-0+z!V+jqy5(*CvN z#Xa&(zS|=+b$E;RFc~z};uN28m$!V=b<*CZhE{8*qHshuakrw;zN-&6vgI^nBfAzx zD?IT5x}HN5v8JW9<+yI+lvF3n4Lwg?YEMayXW!SW{&(6G!deijpn>DTCUv-@2c7s} z^HVMdhS*Jl)FQu^41FZ_Zb3F{10K66Vm!^S{uT2ED@Jm6dJLx4-;t3IlR^wc zYjLU}Yn1dv^wPkhYW^MEuq`2axfFvN*Q=qHLsM+76J~!nchnw=x7J!to;XF^a97v1 zf<+hETDBlRc-WomQ-!V^`jNI;^U9uWdC0$btYWQ!N?;VyY>V#N&ivmxm}oNA9J%tQ zU5_v=BX`bWM~uRY7a4(9GSj^E0-;;0-HuBMAU!RN{Pks=x^8{pnO}O#_W8NNP+*yJ zS>gJ}nEg}Oo!Q8vkQ*{86PmvwqW@YlbH3`Cbf;akVUod<@Z`Cj$9`p+4oKd$7hY*G^U$lk5Es61bKki@u zVn<$;6m7&7^^8q;$ZJ(|`7F_ws)I#2tQ#e2W(Txy2C!fQ`I>qDqHvgkv+h>6J7+e; zCYPyenr4yC6WFgzvpG;DlPVPWYVEQKOMaugdJ8Qx-8iP8XSZuf!jLn{+0&7oW;mKDn303E33mKwld4IH66S8{Qz{?sd0Vl)|YXfjJobj%Wq=$^dxvQ*v zr*%^2ZE(*LaNR(aFc{eF(;4`fpieVMFh>4C-VT~7I~)#)I$%k_-(EpGqwLPh#UGv%UH%Yj z?#dNbC()$_FtH{&b^<1)HCLGsZEHPax8(uUl7qOT0-9Ec$$tCbDd62#730h<91 zzcYob?@hq$X;cB#tYwTjOYs2g=Dt-d)i zGxL)83ky6A3%vVkB*vK|sY7u2%KZg@dRaqb@i6SH=ms&|0n7~&5;MIzR?x>+{uGTt z`eiVj3m2iYlUrZaK_C;(05bsWpItK@ITZ})MQ%x8K$~F`V=Dm>;$1$b)4b5kN)=ccXeow*A#>mv-YUZc`koG|w)b3e}>m!t;g# zlo%R_I*=Z#E^fZT*zN}%lq_sM-Ql+7WV zf$&>P@$*;DtzMB{Nyq?Ro#2D*RGwto=qf7W$FPupLl!q*?494N>5j+TE7Y89>bXGs zPnMK?ZEk4y(#r`LGYBY)ozx{)z>YkX&f|8uOJWw+XoJ(xo^`YaTfMVRpk`((Rd>i5 z@+JZE?1PBQYC*%YNc2Z&8cA#r{uan`CX4*qQ10TXQ??84No}}B$+I!E*fWa%JX~+@ zC%6a*1@kiVWF=);&b#2WEXRd2BC@Xo_{=VvW-3rz2(9Yn@}^$;`hItgW{4l`EKu&2NZ9J=%@SKR?n>p|Ivy9UD3Z+c z`uOxm#W#NGN4`|4WxeTlK^dQyQ+^R@Q!-keW_}pE6QlgE^%)XRUrWv+LiVhVHOzXe z)0`NI-wP3wJN(LSP0Hq{I0c^WesR3qkg6XW6HA6vdh}=$t-g0Sw>sKnFt3}6H7>0A z%FyvSdqR1RAX$lv(&!uaB!$Z!(c76T85! z@x-vkZ#qO=RfF4X3u4vwqjM*a_y0v2Dt_-x z`_Ywtpr8w!8O7UKsQNMtfAAF3Sv_5i92HAB3j03?*I?sYQ$*;_&~kYTkR(d+izHOcEmmdZc|J?$j237w={dapZ`>w=i*OKM2&Uzt(}O5$!uwqL2vzPL ziMDM(wQ2x|&*^U1GTQD9qnu)`wO4-aKj zuRo)0!YI5hLH)6FwYS}q=J}2MWFmBULBdaztD{0BxC{s0m8EPcb!h4$@PAr+V70a< zP>zH-z#dPx<^S5|x+-`#=szcbP;yO?C$2f-X$+lT|w?`Q+m(VO- z3P*@Sw7g#;AB(l2`4)mh`z+%x@blU!&*z4RA94HzTV^+bjNkI=Imf*B{KWr}A=!e_Hx!|rA-ly|7`WjXh71d6A+r_Ma$kR=eT#OHhJqfd1*B@C6$|Du*YO0{Q}e=a`I-8&`?^CkaGOU5md_BRjDQhCamW)!FbB%uHz3)#B4EaYKJXkHbWKwwvJ z$_7?k9Q2+_AvH}1ui&1}?PkrJn%Ul-G}Te|#fn+EhpQrCA@b6cry(HovzVqw zTr4a(>R9SY?B1>XRN`gff9g4}F6-y+mj^A`Kg*-1p7o`ux|1gv4`$pS>>`?Q

^! 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 literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/payment_new/bni.png b/TA_android/assets/images/payment_new/bni.png new file mode 100644 index 0000000000000000000000000000000000000000..6542adf01ac8f7f10a8576408622c76539843d01 GIT binary patch literal 49369 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 z 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 literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/payment_new/mastercard.png b/TA_android/assets/images/payment_new/mastercard.png new file mode 100644 index 0000000000000000000000000000000000000000..489d836229efa9c2d2f4afaee99fec960698717c GIT binary patch literal 20512 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≻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

J&>c_n8c+Nim@c4r%`=*0B+K#>$j2_hkv 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 Cv8vMm literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/tailor_1.png b/TA_android/assets/images/tailor_1.png new file mode 100644 index 0000000000000000000000000000000000000000..6f149094b3ee631588eb97143893f896215316bd GIT binary patch literal 8661 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 ~dsNd$|!mlM0VI8Z*QG8ZV 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± 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�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

mi!@ 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�IuVV@=H`L7IP)p(w`6H^J=;I{; z{Hp$?7QhetNq? zAp7~hWhMMQk@zuRyZa<>7Gx zVjDXs5dUN%NZ^2M7fA42uEEF?W4xu+c>b}N<&%%Yvy9vYbt20x`!qIe9J${OBF*$w z`|LF2gmP0QTqqhVCq>tvx|91D=UywII>hLPUaGXrk5I$@?coWHy~&Zb*K&(_DLeFC z`z=Qc9eJH1FI)IdaW@N~M=b!)7_Lwok@O(0`@jSQ3(}x))kWQ z7JA;ChuxBf@s9S?M)@`-xXSq>xof=j@v}m48aa6`0rF{uCS+1$(p%z?$GoqQtC3Nf zBwDfPf^^Qp+%jJvpz&331q?;1>#N5dHDhS-TSOHWaI;_0{iO^it1T2w*mtqfT4nAFlUt>pJO@nUW`OwRrawdG6DV7-!l7YexyP_ zc7g-(cE9B%5QI$Y6jSsuQ;umcq7B{6EQKcZf{{`K@Jnyr~GmTDW#G6Z{EdE#A;VdeWOuWUS-{6&a=DR z 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 literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/tailor_default.png b/TA_android/assets/images/tailor_default.png new file mode 100644 index 0000000000000000000000000000000000000000..a181ac87a71970c862eaa0a7298d32019d132c8c GIT binary patch literal 88197 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%0DO*NZfF<>Y%yfE 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%0Dxfzi@>$q{dOdDVhXe?Eat{qtWaXtaUkC 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 + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/TA_android/ios/Flutter/Debug.xcconfig b/TA_android/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/TA_android/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/TA_android/ios/Flutter/Release.xcconfig b/TA_android/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/TA_android/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/TA_android/ios/Runner.xcodeproj/project.pbxproj b/TA_android/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8499b8d --- /dev/null +++ b/TA_android/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,616 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/TA_android/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TA_android/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/TA_android/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/TA_android/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/TA_android/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/TA_android/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..8e3ca5d --- /dev/null +++ b/TA_android/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TA_android/ios/Runner.xcworkspace/contents.xcworkspacedata b/TA_android/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/TA_android/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/TA_android/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/TA_android/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/TA_android/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/TA_android/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/TA_android/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/TA_android/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/TA_android/ios/Runner/AppDelegate.swift b/TA_android/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..9074fee --- /dev/null +++ b/TA_android/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d0d98aa --- /dev/null +++ b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1 @@ +{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} \ No newline at end of file diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..f9930d43583fe90360870f172a9b7ae8fe92fe12 GIT binary patch literal 5334 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7&w@K)Q9>#R~Q&X=6bp~hE&XXd)<(cL4oIh zLEq2qHZcb-x;WlH_fC$1VL@UYJ5cd^2_V5?2qXlOfP}&kAmPx#$iUDbzzk$6vH=Mv z9w5;&s&F)TMia$oRv0ZQM$5<1T4A)(9BnF$HjqY}g`=(J(Z0fH4{5XmIofR=9V{3f mA_3-t(PrUjvygDJQ2bqt(7!b|?|A`J41=eupUXO@geCx??HgDC literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba8dba2708edcb50ac9df0d028e8da538ebf72f GIT binary patch literal 86 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1SFYWcSQjySx*bP0l+XkKbuJi+ literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..beb6f8b8061728d3a93a2f6a4c6409224ee2ccb4 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1SFZ~=vx6PeNPw1kcv5P&l>VFFmNy%^!?m! wlQLn#HHXV(dQVbByN@PqjL;E-Que*#^E8;}UGNS$2-M2p>FVdQ&MBb@02_@SCIA2c literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..0185a7b68c96e439343e0dcd3dac8182d6480859 GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1SGf4^HT*Iv{>-nlb+S7YV<)cj2w$RoN%Un`iR&&U;FVdQ I&MBb@08$_@`Tzg` literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..10fb91ebc0700aa5e4cc1d7ea9b7fa69583e83ea GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^vLMXC1SD^M{15@8G(24#Ln`LHJ!8nrz`((5(D!q@ vjm?A)TbX8U`>Y_p^7`wqReR&sf6rl56Jsut&Jdae)WhKE>gTe~DWM4f=K&rC literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..852e75568f773a9266ae8eece7249c37b382c1c4 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^Rv^s51SIor-mM2x;hrvzAr*7po-^cSP!M1+Wcw3c zXJQb;;kkN2b=o!iZ?6x?-kp@^xqV6WCEb_PO1yWe62-N8ZN~hJm2-Ip&O7T!GYn(0h>4b zp9&{d2NVQ3&UiiN^84NQH{an^LB{Ts5ZZb^G literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..beb6f8b8061728d3a93a2f6a4c6409224ee2ccb4 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1SFZ~=vx6PeNPw1kcv5P&l>VFFmNy%^!?m! wlQLn#HHXV(dQVbByN@PqjL;E-Que*#^E8;}UGNS$2-M2p>FVdQ&MBb@02_@SCIA2c literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..242196672a5907bf4c4349bdd88e965bb781e4aa GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^0U*r51SA=YQ-1-eQcoAhkcv5P&pYxmC6+|_>l@Z3#vb0)R!X@5GY>0^-CX0hqCf{Qc)I$z JtaD0e0swHkMbZEO literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e806e2e7352cd98879c0ce27648e7658341b0d3d GIT binary patch literal 342 zcmeAS@N?(olHy`uVBq!ia0vp^6(G#P1SGeyEo^0AV3hTAaSW-L^Y((FAcKOy0Ry%_ z(RCpKY(lJi-_4A?vpt^u&!HC`7X=q9ySexDNyr*nC6yc*F#?vkJuLTRx2Goq!;8Vw L)z4*}Q$iB}wN8Ok literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..8193c0968b8de09e1141e50cb32a98c2e58c4404 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1SBWM%0B~AKAtX)Ar*7po>OFGP!M1+WcjOY y&uXyTA%}BYdfMOg{d{*aMWb577KUaJreyweGavK6_$nG`E`z75pUXO@geCwVkSM|c literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..01fb869d7d35b0bce7845f3555e33e7941e614fa GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^DImpqS wPdl4xJ16)A>`G57OyAGn~%@(!E1^Su6)78&qol`;+0Q2i`xBvhE literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..bbe5793cdca8ad0d9d77a760cc48706ba87cf432 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^mLSZ*1SFZOL@oiT2u~Nskcv5P&l&PECt#VoB7crrjJ{Ib})Fl L`njxgN@xNAA_+Jj literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ec318e464110857a834eb3c21dd73674b09bda83 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^MIg+<1SA>u3u!ShFbaCQIEGZrd3)g?Cxe2(0R#DW z`#bP0 Hl+XkK3%jql literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..5bec4366709ba1130345df582b6c8ef9d9261175 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1SD_us|Wz8Tu&Frkcv5P&pYxmC2rC;GDF|wS;tIzGo>z@EF)XsEMu`Pi(HyZo*&R+22WQ% Jmvv4FO#tq`Jm&xa literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8030b280221f7316521b7e5fdf8f9bd08e79b795 GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q2}owBl)h(RU`+OOaSW-L^Y-FKP6h*>0~`2$ z{(t(V&F`o}Y{G{(?-nN4v41$WLE>-{Pq(4YD1)p((0g`^)h_b3-eF*Aon@H za!13HOTib;y_389hp%Fxr|aY{HBn!!Ss^AXGlDKISwxXQOynmPy{$JZ!+>@(c)I$z JtaD0e0synlJr)1} literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/TA_android/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..34af5db0bd1863661febb7a1bc8b38da12aeaee5 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0vp^GeDSw2}n*~u)U0dfw9!n#WAE}&fALzIT;iL4j9P4 z+y7~2i^8;&Ca3RbbpCCRXD?`c6x3qOw_&$IQF6N6wTou*c{Z?LF~T>3a7lgI-Ry{S+`S#Cj;Y&!PC{xWt~$( F6998%>ly$6 literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/TA_android/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/TA_android/ios/Runner/Base.lproj/LaunchScreen.storyboard b/TA_android/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/TA_android/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TA_android/ios/Runner/Base.lproj/Main.storyboard b/TA_android/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/TA_android/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TA_android/ios/Runner/Info.plist b/TA_android/ios/Runner/Info.plist new file mode 100644 index 0000000..070eec3 --- /dev/null +++ b/TA_android/ios/Runner/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Tailorhub + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tailorhub + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + + NSLocationWhenInUseUsageDescription + TailorHub memerlukan akses lokasi Anda untuk menampilkan penjahit terdekat di sekitar Anda. + NSLocationAlwaysUsageDescription + TailorHub memerlukan akses lokasi Anda untuk menampilkan penjahit terdekat di sekitar Anda. + + diff --git a/TA_android/ios/Runner/Runner-Bridging-Header.h b/TA_android/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/TA_android/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/TA_android/ios/RunnerTests/RunnerTests.swift b/TA_android/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/TA_android/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/TA_android/lib/core/controllers/auth_controller.dart b/TA_android/lib/core/controllers/auth_controller.dart new file mode 100644 index 0000000..77fe77d --- /dev/null +++ b/TA_android/lib/core/controllers/auth_controller.dart @@ -0,0 +1,980 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../services/api_service.dart'; +import '../providers/user_provider.dart'; +import '../services/auth_service.dart'; +// ignore_for_file: avoid_print + +class AuthController { + final TextEditingController emailController = TextEditingController(); + final TextEditingController nameController = TextEditingController(); + final TextEditingController phoneController = TextEditingController(); + final TextEditingController addressController = TextEditingController(); + final TextEditingController passwordController = TextEditingController(); + final TextEditingController confirmPasswordController = + TextEditingController(); + final TextEditingController storeNameController = TextEditingController(); + final TextEditingController experienceController = TextEditingController(); + final TextEditingController shopDescriptionController = + TextEditingController(); + final TextEditingController latitudeController = TextEditingController(); + final TextEditingController longitudeController = TextEditingController(); + + List selectedSpecializations = []; + List> availableSpecializations = []; + bool isLoading = false; + + // Map untuk menyimpan error validasi + Map validationErrors = {}; + + AuthController() { + _loadSpecializations(); + } + + bool validateLoginInputs(BuildContext context) { + if (emailController.text.isEmpty || passwordController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Email dan password harus diisi')), + ); + return false; + } + return true; + } + + bool validateRegistrationInputs(BuildContext context, + {bool isTailor = false}) { + // Reset error validasi sebelumnya + validationErrors.clear(); + bool isValid = true; + + // Validasi email + if (emailController.text.isEmpty) { + validationErrors['email'] = 'Email tidak boleh kosong'; + isValid = false; + } else if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$') + .hasMatch(emailController.text)) { + validationErrors['email'] = 'Format email tidak valid'; + isValid = false; + } + + // Validasi nama + if (nameController.text.isEmpty) { + validationErrors['name'] = 'Nama tidak boleh kosong'; + isValid = false; + } + + // Validasi no handphone + if (phoneController.text.isEmpty) { + validationErrors['phone'] = 'Nomor handphone tidak boleh kosong'; + isValid = false; + } else if (!RegExp(r'^[0-9]{10,13}$').hasMatch(phoneController.text)) { + validationErrors['phone'] = 'Nomor handphone tidak valid (10-13 digit)'; + isValid = false; + } + + // Validasi alamat + if (addressController.text.isEmpty) { + validationErrors['address'] = 'Alamat tidak boleh kosong'; + isValid = false; + } + + // Validasi password + if (passwordController.text.isEmpty) { + validationErrors['password'] = 'Password tidak boleh kosong'; + isValid = false; + } else if (passwordController.text.length < 8) { + validationErrors['password'] = 'Password minimal 8 karakter'; + isValid = false; + } + + // Validasi konfirmasi password + if (confirmPasswordController.text.isEmpty) { + validationErrors['confirm_password'] = + 'Konfirmasi password tidak boleh kosong'; + isValid = false; + } else if (passwordController.text != confirmPasswordController.text) { + validationErrors['confirm_password'] = 'Password tidak cocok'; + isValid = false; + } + + // Validasi spesifik untuk penjahit + if (isTailor) { + if (storeNameController.text.isEmpty) { + validationErrors['store_name'] = 'Nama toko tidak boleh kosong'; + isValid = false; + } + + if (experienceController.text.isEmpty) { + validationErrors['experience'] = 'Pengalaman tidak boleh kosong'; + isValid = false; + } else if (!RegExp(r'^[0-9]+$').hasMatch(experienceController.text)) { + validationErrors['experience'] = 'Pengalaman harus berupa angka'; + isValid = false; + } + + if (shopDescriptionController.text.isEmpty) { + validationErrors['shop_description'] = + 'Deskripsi toko tidak boleh kosong'; + isValid = false; + } + } + + // Tampilkan error dalam dialog jika ada error validasi + if (!isValid) { + showValidationErrorDialog(context); + } + + return isValid; + } + + bool validateForgotPassword(BuildContext context) { + if (emailController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Email tidak boleh kosong')), + ); + return false; + } + return true; + } + + Future logout([BuildContext? context]) async { + print('DEBUG: Memulai proses logout...'); + try { + // Reset semua controller + print('DEBUG: Mereset semua controller...'); + emailController.clear(); + nameController.clear(); + phoneController.clear(); + addressController.clear(); + passwordController.clear(); + confirmPasswordController.clear(); + storeNameController.clear(); + experienceController.clear(); + shopDescriptionController.clear(); + latitudeController.clear(); + longitudeController.clear(); + selectedSpecializations.clear(); + availableSpecializations.clear(); + print('DEBUG: Semua controller berhasil direset'); + + // Hapus data user dari provider jika context tersedia + if (context != null) { + print('DEBUG: Membersihkan data user dari provider...'); + try { + await Provider.of(context, listen: false).clearUser(); + print('DEBUG: Data user berhasil dihapus dari provider'); + } catch (e) { + print('ERROR saat menghapus data user dari provider: $e'); + } + } else { + print( + 'DEBUG: Context tidak tersedia, melewati pembersihan user provider'); + } + + // Panggil API logout untuk menghapus token autentikasi + print('DEBUG: Memanggil ApiService.logout()...'); + try { + await AuthService.clearAuthData(); + print('DEBUG: Token autentikasi berhasil dihapus'); + } catch (e) { + print('ERROR saat menghapus token autentikasi: $e'); + } + + print('DEBUG: Proses logout selesai'); + } catch (e) { + print('ERROR KRITIS pada proses logout: $e'); + print('Stack trace: ${StackTrace.current}'); + } + } + + void dispose() { + emailController.dispose(); + nameController.dispose(); + phoneController.dispose(); + addressController.dispose(); + passwordController.dispose(); + confirmPasswordController.dispose(); + storeNameController.dispose(); + experienceController.dispose(); + shopDescriptionController.dispose(); + latitudeController.dispose(); + longitudeController.dispose(); + } + + Future _loadSpecializations() async { + availableSpecializations = await ApiService.getSpecializations(); + } + + void toggleSpecialization(int id) { + if (selectedSpecializations.contains(id)) { + selectedSpecializations.remove(id); + } else { + selectedSpecializations.add(id); + } + } + + Future loginTailor(BuildContext context) async { + if (!validateLoginInputs(context)) return false; + + isLoading = true; + + try { + final result = await ApiService.loginTailor( + email: emailController.text.trim(), + password: passwordController.text, + ); + + isLoading = false; + + // Tampilkan respons lengkap untuk debugging + print('DEBUG LOGIN FULL RESPONSE: ${result.toString()}'); + + if (result['success'] == true) { + // Verifikasi token tersimpan dengan benar + final token = await ApiService.getToken(); + if (token == null || token.isEmpty) { + print( + 'WARNING: Token tidak berhasil disimpan setelah login penjahit berhasil'); + } + + print( + 'DEBUG AUTH: Respons login sukses, struktur data: ${result.keys.join(', ')}'); + + // Simpan data user ke UserProvider + if (result.containsKey('user') && result['user'] is Map) { + var userData = result['user'] as Map; + print( + 'DEBUG AUTH: User data dari "user": ${userData.keys.join(', ')}'); + if (userData.containsKey('profile_photo')) { + print( + 'DEBUG AUTH: Profile photo dari data user: ${userData['profile_photo']}'); + } + + await Provider.of(context, listen: false) + .setUser(userData); + + print('DEBUG AUTH: User data saved to provider from "user" key'); + } else if (result.containsKey('data') && + result['data'] is Map && + (result['data'] as Map).containsKey('user')) { + var userData = + (result['data'] as Map)['user'] as Map; + print( + 'DEBUG AUTH: User data dari "data.user": ${userData.keys.join(', ')}'); + if (userData.containsKey('profile_photo')) { + print( + 'DEBUG AUTH: Profile photo dari data.user: ${userData['profile_photo']}'); + } + + await Provider.of(context, listen: false) + .setUser(userData); + + print('DEBUG AUTH: User data saved to provider from "data.user" key'); + } else { + print('WARNING: Data user tidak ditemukan dalam respons login'); + if (result.containsKey('data')) { + print('DEBUG AUTH: Konten "data": ${result['data']}'); + } + } + + // Simpan data autentikasi + if (token != null) { + await AuthService.saveAuthData( + token, + 'penjahit', + result['user']['id'], + ); + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + return true; + } else { + // Cek apakah error terkait email belum diverifikasi + if (result.containsKey('data') && + result['data'] is Map && + (result['data'] as Map).containsKey('error')) { + + final errorMsg = result['data']['error'].toString(); + if (errorMsg.contains('Email belum diverifikasi')) { + // Ekstrak email dari pesan error + final emailMatch = RegExp(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}') + .firstMatch(errorMsg); + final email = emailMatch != null ? emailMatch.group(0) : emailController.text.trim(); + + // Tampilkan dialog email belum diverifikasi dengan respons lengkap + showEmailVerificationDialog(context, email ?? '', result); + return false; + } + } + + // Jika bukan error email belum diverifikasi, tampilkan dialog error login + showErrorDialog(context, 'Login Gagal', + 'Pesan: ${result['message']}\n\n${result['data'] != null ? 'Detail: ${result['data']}' : ''}'); + return false; + } + } catch (e) { + isLoading = false; + print('ERROR login penjahit: $e'); + showErrorDialog(context, 'Terjadi Kesalahan', 'Error: $e'); + return false; + } + } + + Future registerTailor(BuildContext context) async { + // Validasi dasar input + if (!validateRegistrationInputs(context, isTailor: true)) return false; + + // Validasi tambahan untuk spesialisasi + if (selectedSpecializations.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Pilih minimal satu spesialisasi'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + isLoading = true; + + try { + // Log data yang akan dikirimkan + print('Sending registration data to API:'); + print('Name: ${nameController.text.trim()}'); + print('Email: ${emailController.text.trim()}'); + print('Phone: ${phoneController.text.trim()}'); + print('Store: ${storeNameController.text.trim()}'); + print('Experience: ${experienceController.text.trim()}'); + print('Address: ${addressController.text.trim()}'); + print('Shop Description: ${shopDescriptionController.text.trim()}'); + print('Specializations: $selectedSpecializations'); + + // Parsing latitude dan longitude jika ada + double? latitude; + double? longitude; + + if (latitudeController.text.isNotEmpty) { + latitude = double.tryParse(latitudeController.text); + print('Latitude: $latitude'); + } + + if (longitudeController.text.isNotEmpty) { + longitude = double.tryParse(longitudeController.text); + print('Longitude: $longitude'); + } + + final result = await ApiService.registerTailor( + name: nameController.text.trim(), + email: emailController.text.trim(), + password: passwordController.text, + passwordConfirmation: confirmPasswordController.text, + phoneNumber: phoneController.text.trim(), + address: addressController.text.trim(), + shopDescription: shopDescriptionController.text.trim(), + latitude: latitude, + longitude: longitude, + specializations: selectedSpecializations, + ); + + isLoading = false; + + print('Registration result: $result'); + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + return true; + } else { + String errorMessage = + result['message'] ?? 'Terjadi kesalahan saat registrasi'; + + // Cek apakah ada pesan error spesifik + if (result.containsKey('errors')) { + try { + final errors = result['errors'] as Map; + if (errors.isNotEmpty) { + errorMessage = ''; + validationErrors.clear(); // Reset validasi errors + + errors.forEach((key, value) { + if (value is List && value.isNotEmpty) { + // Format field name untuk tampilan yang lebih baik + String fieldName = key.replaceAll('_', ' '); + fieldName = + fieldName[0].toUpperCase() + fieldName.substring(1); + + String errorMsg = '• $fieldName: ${value.first}'; + errorMessage += '$errorMsg\n'; + validationErrors[key] = value.first.toString(); + } else if (value is String) { + String errorMsg = '• $key: $value'; + errorMessage += '$errorMsg\n'; + validationErrors[key] = value; + } + }); + + // Tampilkan dialog error registrasi + showRegistrationErrorDialog(context); + } + } catch (e) { + print('Error processing error messages: $e'); + } + } else { + // Jika tidak ada errors detail, tampilkan pesan umum + showErrorDialog(context, 'Registrasi Gagal', errorMessage); + } + + return false; + } + } catch (e) { + isLoading = false; + print('Exception during tailor registration: $e'); + showErrorDialog(context, 'Terjadi Kesalahan', 'Error: $e'); + return false; + } + } + + // Metode login untuk customer dengan UserProvider + Future loginCustomer(BuildContext context) async { + if (!validateLoginInputs(context)) return false; + + isLoading = true; + + try { + final result = await ApiService.loginCustomer( + email: emailController.text.trim(), + password: passwordController.text, + ); + + isLoading = false; + + // Tampilkan respons lengkap untuk debugging + print('DEBUG LOGIN FULL RESPONSE: ${result.toString()}'); + + if (result['success'] == true) { + // Verifikasi token tersimpan dengan benar + final token = await ApiService.getToken(); + if (token == null || token.isEmpty) { + print( + 'WARNING: Token tidak berhasil disimpan setelah login berhasil'); + } + + // Simpan data user ke UserProvider + if (result.containsKey('user') && result['user'] is Map) { + await Provider.of(context, listen: false) + .setUser(result['user'] as Map); + } else if (result.containsKey('data') && + result['data'] is Map && + (result['data'] as Map).containsKey('user')) { + await Provider.of(context, listen: false) + .setUser((result['data'] as Map)['user'] as Map); + } else { + print('WARNING: Data user tidak ditemukan dalam respons login'); + } + + // Simpan data autentikasi + if (token != null) { + await AuthService.saveAuthData( + token, + 'pelanggan', + result['user']['id'], + ); + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + return true; + } else { + // Cek apakah error terkait email belum diverifikasi + if (result.containsKey('data') && + result['data'] is Map && + (result['data'] as Map).containsKey('error')) { + + final errorMsg = result['data']['error'].toString(); + if (errorMsg.contains('Email belum diverifikasi')) { + // Ekstrak email dari pesan error + final emailMatch = RegExp(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}') + .firstMatch(errorMsg); + final email = emailMatch != null ? emailMatch.group(0) : emailController.text.trim(); + + // Tampilkan dialog email belum diverifikasi + showEmailVerificationDialog(context, email ?? '', result); + return false; + } + } + + // Jika bukan error email belum diverifikasi, tampilkan dialog error login + showErrorDialog(context, 'Login Gagal', + 'Pesan: ${result['message']}\n\n${result['data'] != null ? 'Detail: ${result['data']}' : ''}'); + return false; + } + } catch (e) { + isLoading = false; + print('ERROR login: $e'); + showErrorDialog(context, 'Terjadi Kesalahan', 'Error: $e'); + return false; + } + } + + // Metode register untuk customer + Future registerCustomer(BuildContext context) async { + // Validasi dasar input + if (!validateRegistrationInputs(context)) return false; + + // Validasi tambahan untuk spesialisasi + if (selectedSpecializations.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Pilih minimal satu model jahit'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + // Validasi lokasi + if ((latitudeController.text.isEmpty && + longitudeController.text.isNotEmpty) || + (latitudeController.text.isNotEmpty && + longitudeController.text.isEmpty)) { + validationErrors['location'] = + 'Latitude dan longitude harus diisi keduanya'; + showValidationErrorDialog(context); + return false; + } + + // Jika tidak ada lokasi yang dimasukkan sama sekali, beritahu pengguna + if (latitudeController.text.isEmpty && longitudeController.text.isEmpty) { + // Tampilkan dialog konfirmasi untuk melanjutkan tanpa lokasi + bool continueWithoutLocation = + await _showNoLocationConfirmationDialog(context); + if (!continueWithoutLocation) { + return false; + } + } + + isLoading = true; + + try { + // Log data yang akan dikirimkan + print('Sending customer registration data to API:'); + print('Name: ${nameController.text.trim()}'); + print('Email: ${emailController.text.trim()}'); + print('Phone: ${phoneController.text.trim()}'); + print('Address: ${addressController.text.trim()}'); + print('Preferred Specializations: $selectedSpecializations'); + + // Parsing latitude dan longitude jika ada + double? latitude; + double? longitude; + + if (latitudeController.text.isNotEmpty) { + latitude = double.tryParse(latitudeController.text); + print('Latitude: $latitude'); + } else { + print('WARNING: Latitude controller text kosong!'); + } + + if (longitudeController.text.isNotEmpty) { + longitude = double.tryParse(longitudeController.text); + print('Longitude: $longitude'); + } else { + print('WARNING: Longitude controller text kosong!'); + } + + final result = await ApiService.registerCustomer( + name: nameController.text.trim(), + email: emailController.text.trim(), + password: passwordController.text, + phoneNumber: phoneController.text.trim(), + address: addressController.text.trim(), + latitude: latitude, + longitude: longitude, + preferredSpecializations: selectedSpecializations, + ); + + isLoading = false; + + print('Customer registration result: $result'); + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + return true; + } else { + String errorMessage = + result['message'] ?? 'Terjadi kesalahan saat registrasi'; + + // Cek apakah ada pesan error spesifik + if (result.containsKey('errors') && result['errors'] != null) { + try { + final errors = result['errors'] as Map; + if (errors.isNotEmpty) { + errorMessage = ''; + validationErrors.clear(); // Reset validasi errors + + errors.forEach((key, value) { + if (value is List && value.isNotEmpty) { + // Format field name untuk tampilan yang lebih baik + String fieldName = key.replaceAll('_', ' '); + fieldName = + fieldName[0].toUpperCase() + fieldName.substring(1); + + String errorMsg = '• $fieldName: ${value.first}'; + errorMessage += '$errorMsg\n'; + validationErrors[key] = value.first.toString(); + } else if (value is String) { + // Format field name untuk tampilan yang lebih baik + String fieldName = key.replaceAll('_', ' '); + fieldName = + fieldName[0].toUpperCase() + fieldName.substring(1); + + String errorMsg = '• $fieldName: $value'; + errorMessage += '$errorMsg\n'; + validationErrors[key] = value; + } + }); + + // Tampilkan dialog error registrasi + showRegistrationErrorDialog(context); + } + } catch (e) { + print('Error processing error messages: $e'); + showErrorDialog(context, 'Registrasi Gagal', errorMessage); + } + } else { + // Jika tidak ada errors detail, tampilkan pesan umum + showErrorDialog(context, 'Registrasi Gagal', errorMessage); + } + + return false; + } + } catch (e) { + isLoading = false; + print('Exception during customer registration: $e'); + showErrorDialog(context, 'Terjadi Kesalahan', 'Error: $e'); + return false; + } + } + + // Menampilkan dialog error validasi yang lebih jelas + void showValidationErrorDialog(BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.error_outline, color: Colors.red, size: 28), + SizedBox(width: 8), + Text( + 'Form Tidak Lengkap', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Harap perbaiki kesalahan berikut:', + style: TextStyle(fontWeight: FontWeight.w500), + ), + const SizedBox(height: 12), + ...validationErrors.entries.map((entry) => Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.circle, size: 8, color: Colors.red), + const SizedBox(width: 8), + Expanded( + child: Text( + entry.value, + style: TextStyle(color: Colors.red[700]), + ), + ), + ], + ), + )), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text( + 'MENGERTI', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ); + } + + // Menampilkan dialog error registrasi dengan detail validasi + void showRegistrationErrorDialog(BuildContext context) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.error_outline, color: Colors.red, size: 28), + SizedBox(width: 8), + Text( + 'Registrasi Gagal', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Server menolak pendaftaran karena alasan berikut:', + style: TextStyle(fontWeight: FontWeight.w500), + ), + const SizedBox(height: 12), + ...validationErrors.entries.map((entry) => Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.cancel_outlined, + size: 16, color: Colors.red), + const SizedBox(width: 8), + Expanded( + child: Text( + entry.value, + style: TextStyle(color: Colors.red[700]), + ), + ), + ], + ), + )), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text( + 'MENGERTI', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ); + } + + // Menampilkan dialog error umum + void showErrorDialog(BuildContext context, String title, String message) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Row( + children: [ + const Icon(Icons.error_outline, color: Colors.red, size: 28), + const SizedBox(width: 8), + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + content: Text(message), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text( + 'TUTUP', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ); + } + + // Menampilkan dialog konfirmasi untuk mendaftar tanpa lokasi + Future _showNoLocationConfirmationDialog(BuildContext context) async { + bool result = false; + await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.location_off, color: Colors.orange, size: 28), + SizedBox(width: 8), + Text( + 'Lokasi Tidak Diatur', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Anda belum mengatur lokasi (koordinat) untuk akun Anda.', + style: TextStyle(fontSize: 16), + ), + const SizedBox(height: 12), + Text( + 'Lokasi dibutuhkan untuk memudahkan menemukan penjahit terdekat.', + style: TextStyle(color: Colors.grey[700], fontSize: 14), + ), + const SizedBox(height: 8), + const Text( + 'Apakah Anda ingin melanjutkan pendaftaran tanpa lokasi?', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + result = false; + Navigator.pop(context); + }, + child: Text( + 'BATAL', + style: TextStyle( + color: Colors.grey[700], + fontWeight: FontWeight.bold, + ), + ), + ), + ElevatedButton( + onPressed: () { + result = true; + Navigator.pop(context); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + ), + child: const Text('LANJUTKAN'), + ), + ], + ), + ); + return result; + } + + // Fungsi publik untuk menampilkan dialog konfirmasi lokasi + Future showNoLocationConfirmationDialog(BuildContext context) { + return _showNoLocationConfirmationDialog(context); + } + + // Update tampilan dialog verifikasi email untuk tidak menampilkan respons API + void showEmailVerificationDialog(BuildContext context, String email, Map apiResponse) { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + Icons.email_outlined, + size: 64, + color: Color(0xFF1A2552), + ), + const SizedBox(height: 16), + const Text( + 'Email Belum Diverifikasi', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 12), + Text( + 'Kami telah mengirimkan ulang email verifikasi ke $email', + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 14), + ), + const SizedBox(height: 16), + const Text( + 'Silakan periksa email Anda dan klik tautan verifikasi untuk mengaktifkan akun Anda.', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14), + ), + const SizedBox(height: 20), + SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: () => Navigator.pop(context), + child: const Text('Mengerti'), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/TA_android/lib/core/controllers/booking_controller.dart b/TA_android/lib/core/controllers/booking_controller.dart new file mode 100644 index 0000000..8fe42e9 --- /dev/null +++ b/TA_android/lib/core/controllers/booking_controller.dart @@ -0,0 +1,217 @@ +import 'package:flutter/material.dart'; +import 'dart:io'; +import '../services/booking_service.dart'; +import '../models/booking_model.dart'; +// ignore_for_file: avoid_print + +class BookingController extends ChangeNotifier { + List _bookings = []; + List _filteredBookings = []; + bool _isLoading = false; + String? _errorMessage; + bool _disposed = false; + String _currentFilter = 'Semua'; + + List get bookings => _filteredBookings; + bool get isLoading => _isLoading; + String? get errorMessage => _errorMessage; + String get currentFilter => _currentFilter; + + @override + void dispose() { + _disposed = true; + super.dispose(); + } + + @override + void notifyListeners() { + if (!_disposed) { + super.notifyListeners(); + } + } + + void setFilter(String filter) { + _currentFilter = filter; + _applyFilter(); + notifyListeners(); + } + + void _applyFilter() { + if (_currentFilter.toLowerCase() == 'semua') { + _filteredBookings = List.from(_bookings); + return; + } + + _filteredBookings = _bookings.where((booking) { + String status = booking.status.toLowerCase(); + String filter = _currentFilter.toLowerCase(); + + switch (filter) { + case 'reservasi': + return status == 'reservasi'; + case 'diproses': + return status == 'diproses'; + case 'selesai': + return status == 'selesai'; + case 'dibatalkan': + return status == 'dibatalkan'; + default: + return true; + } + }).toList(); + } + + Future loadBookings([String? status]) async { + if (_disposed) return; + + try { + _isLoading = true; + _errorMessage = null; + notifyListeners(); + + print('DEBUG: Loading all bookings from BookingService'); + + // Gunakan metode yang dipindahkan ke BookingService + final result = await BookingService.getCustomerBookings(); + + if (result['success']) { + _bookings = []; + if (result['data'] != null && result['data'] is List) { + for (var item in result['data']) { + try { + _bookings.add(BookingModel.fromJson(item)); + } catch (e) { + print('ERROR: Gagal parsing booking: $e'); + print('ERROR: JSON data: $item'); + } + } + } + + // Terapkan filter + if (status != null && status.isNotEmpty) { + setFilter(status); + } else { + _applyFilter(); + } + + _isLoading = false; + _errorMessage = null; + } else { + _bookings = []; + _filteredBookings = []; + _errorMessage = result['message'] ?? 'Gagal memuat data booking'; + _isLoading = false; + } + + notifyListeners(); + } catch (e, stackTrace) { + print('ERROR: Gagal memuat bookings: $e'); + print('Stack trace: $stackTrace'); + _bookings = []; + _filteredBookings = []; + _errorMessage = 'Terjadi kesalahan: $e'; + _isLoading = false; + notifyListeners(); + } + } + + void clearBookings() { + _bookings = []; + _filteredBookings = []; + _errorMessage = null; + notifyListeners(); + } + + Future> createBooking({ + required int tailorId, + required String appointmentDate, + required String appointmentTime, + required String serviceType, + required String category, + String notes = '', + String paymentMethod = 'transfer_bank', + File? image, + }) async { + try { + print('DEBUG: Membuat booking baru via controller'); + + // Kirim data booking ke API melalui BookingService + final result = await BookingService.createBooking( + tailorId: tailorId, + appointmentDate: appointmentDate, + appointmentTime: appointmentTime, + serviceType: serviceType, + category: category, + notes: notes, + paymentMethod: paymentMethod, + image: image, + ); + + // Jika booking berhasil dibuat, muat ulang daftar booking + if (result['success'] && !_disposed) { + await loadBookings('reservasi'); + } + + return result; + } catch (e, stackTrace) { + print('ERROR: Gagal membuat booking: $e'); + print('Stack trace: $stackTrace'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + Future> rateBooking( + int bookingId, int rating, String review) async { + try { + print( + 'DEBUG: Attempting to rate booking #$bookingId with rating $rating'); + final result = + await BookingService.rateBooking(bookingId, rating, review); + + if (result['success'] && !_disposed) { + await loadBookings(); + } + + return result; + } catch (e) { + print('ERROR: Gagal memberikan rating: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + Future> completeBooking( + int bookingId, + String completionNotes, + String? completionPhoto, + String? pickupDate, + ) async { + try { + print('DEBUG: Menyelesaikan booking #$bookingId melalui controller'); + final result = await BookingService.completeBooking( + bookingId, + completionNotes, + completionPhoto, + pickupDate, + ); + + if (result['success'] && !_disposed) { + // Jika berhasil, muat ulang booking dengan filter 'diproses' + await loadBookings('diproses'); + } + + return result; + } catch (e) { + print('ERROR: Gagal menyelesaikan pesanan: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } +} diff --git a/TA_android/lib/core/controllers/category_controller.dart b/TA_android/lib/core/controllers/category_controller.dart new file mode 100644 index 0000000..50cf7c9 --- /dev/null +++ b/TA_android/lib/core/controllers/category_controller.dart @@ -0,0 +1,76 @@ + +class CategoryController { + // Pilihan kategori yang dipilih + final List selectedCategories = List.generate(8, (index) => false); + + // Nama kategori sesuai gambar yang diberikan + final List categories = [ + 'Celana', + 'Gamis', + 'Gaun', + 'Jas Blazer', + 'Kebaya', + 'Kemeja', + 'Rok', + 'Seragam', + ]; + + // Nama file gambar kategori + final List categoryImages = [ + 'model_jahit/celana.png', + 'model_jahit/gamis.png', + 'model_jahit/gaun.png', + 'model_jahit/jasblezer.png', + 'model_jahit/kebaya.png', + 'model_jahit/kemeja.png', + 'model_jahit/rok.png', + 'model_jahit/seragam.png', + ]; + + // Map untuk menyimpan data dari API, dikelompokkan berdasarkan kategori + final Map>> apiCategories = {}; + + // List untuk menyimpan semua kategori yang tersedia + List categoryGroups = []; + + // Menyimpan data spesialisasi untuk penggunaan nanti + List> allSpecializations = []; + + // Inisialisasi data kategori dari API + void initializeFromApi(List> specializations) { + allSpecializations = specializations; + apiCategories.clear(); + + // Kelompokkan spesialisasi berdasarkan kategori + for (var spec in specializations) { + String category = spec['category'] as String; + + if (!apiCategories.containsKey(category)) { + apiCategories[category] = []; + } + + apiCategories[category]!.add(spec); + } + + // Perbarui list kategori + // ignore_for_file: avoid_print + categoryGroups = apiCategories.keys.toList(); + + print('Initialized ${categoryGroups.length} categories from API'); + print('Categories: $categoryGroups'); + } + + void toggleCategory(int index) { + selectedCategories[index] = !selectedCategories[index]; + } + + List getSelectedCategories() { + List selected = []; + for (int i = 0; i < selectedCategories.length; i++) { + if (selectedCategories[i]) { + selected.add(categories[i]); + } + } + return selected; + } +} diff --git a/TA_android/lib/core/controllers/gallery_controller.dart b/TA_android/lib/core/controllers/gallery_controller.dart new file mode 100644 index 0000000..32db506 --- /dev/null +++ b/TA_android/lib/core/controllers/gallery_controller.dart @@ -0,0 +1,218 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import '../models/gallery_item_model.dart'; +import '../services/api_service.dart'; + +class GalleryController { + final TextEditingController titleController = TextEditingController(); + final TextEditingController descriptionController = TextEditingController(); + final TextEditingController categoryController = TextEditingController(); + + List galleryItems = []; + bool isLoading = false; + + // Dispose metode + void dispose() { + titleController.dispose(); + descriptionController.dispose(); + categoryController.dispose(); + } + + // Reset input fields + void resetFields() { + titleController.clear(); + descriptionController.clear(); + categoryController.clear(); + } + + // Mengambil daftar galeri + Future fetchGalleryItems(BuildContext context) async { + isLoading = true; + + try { + final result = await ApiService.getTailorGallery(); + + isLoading = false; + + if (result['success']) { + final List data = result['data'] ?? []; + galleryItems = data.map((item) => GalleryItem.fromJson(item)).toList(); + return true; + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + return false; + } + } catch (e) { + isLoading = false; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + return false; + } + } + + // Menambahkan item galeri + Future addGalleryItem(BuildContext context, File photo) async { + if (titleController.text.isEmpty || + descriptionController.text.isEmpty || + categoryController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Semua field harus diisi'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + isLoading = true; + + try { + final result = await ApiService.addTailorGalleryItem( + photo: photo, + title: titleController.text, + description: descriptionController.text, + category: categoryController.text, + ); + + isLoading = false; + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + resetFields(); + return true; + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + return false; + } + } catch (e) { + isLoading = false; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + return false; + } + } + + // Mengupdate item galeri + Future updateGalleryItem(BuildContext context, int id) async { + if (titleController.text.isEmpty || + descriptionController.text.isEmpty || + categoryController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Semua field harus diisi'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + isLoading = true; + + try { + final result = await ApiService.updateTailorGalleryItem( + id: id, + title: titleController.text, + description: descriptionController.text, + category: categoryController.text, + ); + + isLoading = false; + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + resetFields(); + return true; + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + return false; + } + } catch (e) { + isLoading = false; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + return false; + } + } + + // Menghapus item galeri + Future deleteGalleryItem(BuildContext context, int id) async { + isLoading = true; + + try { + final result = await ApiService.deleteTailorGalleryItem(id); + + isLoading = false; + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + return true; + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + return false; + } + } catch (e) { + isLoading = false; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + return false; + } + } + + // Load data ke form untuk edit + void setFormDataForEdit(GalleryItem item) { + titleController.text = item.title; + descriptionController.text = item.description; + categoryController.text = item.category; + } +} diff --git a/TA_android/lib/core/controllers/midtrans_controller.dart b/TA_android/lib/core/controllers/midtrans_controller.dart new file mode 100644 index 0000000..ff1d26d --- /dev/null +++ b/TA_android/lib/core/controllers/midtrans_controller.dart @@ -0,0 +1,275 @@ +import 'package:flutter/material.dart'; +import '../services/midtrans_service.dart'; +// import 'package:url_launcher/url_launcher.dart'; +import '../../pages/costumer/order/midtrans_webview_page.dart'; +// ignore_for_file: avoid_print + +class MidtransController extends ChangeNotifier { + bool _isLoading = false; + bool _isPaymentInitiated = false; + String _errorMessage = ''; + Map _paymentData = {}; + String _redirectUrl = ''; + String _snapToken = ''; + String _paymentStatus = 'unpaid'; + int? _bookingId; + + // Getters + bool get isLoading => _isLoading; + bool get isPaymentInitiated => _isPaymentInitiated; + String get errorMessage => _errorMessage; + Map get paymentData => _paymentData; + String get redirectUrl => _redirectUrl; + String get snapToken => _snapToken; + String get paymentStatus => _paymentStatus; + int? get bookingId => _bookingId; + + // Setters + set errorMessage(String value) { + _errorMessage = value; + notifyListeners(); + } + + set paymentStatus(String value) { + _paymentStatus = value; + notifyListeners(); + } + + // Inisiasi pembayaran Midtrans untuk booking tertentu + Future> initiatePayment(int bookingId) async { + _isLoading = true; + _errorMessage = ''; + _bookingId = bookingId; + notifyListeners(); + + try { + final result = await MidtransService.initiatePayment(bookingId); + + if (result['success'] == true && result['data'] != null) { + _isPaymentInitiated = true; + _paymentData = result['data']; + + // Simpan URL dan token untuk buka website Midtrans + _snapToken = result['data']['snap_token'] ?? ''; + _redirectUrl = result['data']['redirect_url'] ?? ''; + + _errorMessage = ''; + } else { + _isPaymentInitiated = false; + _errorMessage = result['message'] ?? 'Gagal menginisiasi pembayaran'; + } + + _isLoading = false; + notifyListeners(); + + return result; + } catch (e) { + _isLoading = false; + _isPaymentInitiated = false; + _errorMessage = 'Terjadi kesalahan: $e'; + notifyListeners(); + + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Cek status pembayaran booking + Future> checkPaymentStatus(int bookingId) async { + _isLoading = true; + notifyListeners(); + + try { + print('Mengecek status pembayaran untuk booking ID: $bookingId'); + final result = await MidtransService.checkPaymentStatus(bookingId); + + if (result['success'] == true && result['data'] != null) { + _paymentData = result['data']; + _paymentStatus = result['data']['payment_status'] ?? 'unpaid'; + + // Log informasi pembayaran yang lebih lengkap + print('Status pembayaran diterima: $_paymentStatus'); + print('Data pembayaran: $_paymentData'); + + // Periksa apakah sudah dibayar + if (_paymentStatus == 'settlement' || _paymentStatus == 'capture' || _paymentStatus == 'paid') { + print('Pembayaran terdeteksi berhasil'); + } else { + print('Pembayaran belum selesai, status: $_paymentStatus'); + } + + _errorMessage = ''; + } else { + _errorMessage = result['message'] ?? 'Gagal mengecek status pembayaran'; + print('Gagal mengecek status pembayaran: $_errorMessage'); + } + + _isLoading = false; + notifyListeners(); + + return result; + } catch (e) { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + print('Error saat mengecek status pembayaran: $e'); + notifyListeners(); + + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Paksa update status pembayaran menjadi "settlement" + Future forceUpdatePaymentStatus() async { + _paymentStatus = 'settlement'; + notifyListeners(); + } + + // Membuka halaman pembayaran + Future openPaymentPage(BuildContext context) async { + try { + print('Membuka halaman pembayaran WebView dengan URL: $redirectUrl'); + + // Url yang akan ditampilkan jika ada masalah dalam membuka WebView + final fallbackUrl = redirectUrl; + + if (redirectUrl.isEmpty) { + print('ERROR: URL pembayaran kosong'); + Future.microtask(() => notifyListeners()); // Gunakan microtask untuk notifyListeners + return; + } + + // Memastikan domain URL adalah yang diharapkan (Midtrans) + if (!redirectUrl.contains('midtrans') && !redirectUrl.contains('gopay')) { + print('WARNING: URL pembayaran bukan dari Midtrans: $redirectUrl'); + } + + // Buka WebView untuk pembayaran Midtrans + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MidtransWebView( + url: redirectUrl, + onUrlChanged: (String url) { + print('URL saat ini: $url'); + + // Deteksi URL yang menandakan pembayaran berhasil + _checkSuccessIndicators(url); + }, + onWebViewClosed: () { + print('WebView ditutup'); + // Gunakan Future.microtask untuk mencegah notifyListeners saat widget tree terkunci + Future.microtask(() { + // Cek status pembayaran secara manual ketika WebView ditutup + if (_bookingId != null) { + checkPaymentStatus(_bookingId!); + } + }); + }, + ), + ), + ); + + print('Hasil dari WebView: $result'); + + // WebView ditutup, gunakan microtask untuk notifyListeners + Future.microtask(() => notifyListeners()); + } catch (e) { + print('ERROR: Gagal membuka WebView: $e'); + // Set error dan notify listeners menggunakan microtask + _errorMessage = 'Gagal membuka halaman pembayaran: $e'; + Future.microtask(() => notifyListeners()); + } + } + + // Fungsi untuk mendeteksi indikator sukses dari URL + void _checkSuccessIndicators(String url) { + // Gunakan Future.microtask untuk memastikan notifyListeners dipanggil di frame berikutnya + // sehingga tidak terjadi saat widget tree terkunci + Future.microtask(() { + // Deteksi URL yang menandakan pembayaran berhasil + if (url.contains('transaction_status=settlement') || + url.contains('transaction_status=capture') || + url.contains('transaction_status=paid')) { + print('Terdeteksi indikator sukses: ${url.split('transaction_status=')[1].split('&')[0]}'); + // Set status sebagai settlement sementara sampai diverifikasi oleh API + _paymentStatus = 'settlement'; + notifyListeners(); + } else if (url.contains('transaction_status=pending')) { + print('Terdeteksi status pending'); + _paymentStatus = 'pending'; + notifyListeners(); + } else if (url.contains('transaction_status=deny') || + url.contains('transaction_status=cancel') || + url.contains('transaction_status=expire')) { + print('Terdeteksi status gagal: ${url.split('transaction_status=')[1].split('&')[0]}'); + _paymentStatus = url.split('transaction_status=')[1].split('&')[0]; + notifyListeners(); + } + }); + } + + // Fungsi untuk memeriksa status pembayaran secara manual + Future> checkPaymentStatusManual(int bookingId) async { + _isLoading = true; + notifyListeners(); + + try { + print('Memeriksa status pembayaran secara manual untuk booking ID: $bookingId'); + final result = await MidtransService.checkPaymentStatusManual(bookingId); + + if (result['success'] == true && result['data'] != null) { + _paymentData = result['data']; + _paymentStatus = result['data']['payment_status'] ?? 'unpaid'; + + // Log informasi pembayaran yang lebih lengkap + print('Status pembayaran diterima: $_paymentStatus'); + print('Data pembayaran: $_paymentData'); + + // Periksa apakah sudah dibayar + if (_paymentStatus == 'settlement' || _paymentStatus == 'capture' || _paymentStatus == 'paid') { + print('Pembayaran terdeteksi berhasil'); + } else { + print('Pembayaran belum selesai, status: $_paymentStatus'); + } + + _errorMessage = ''; + } else { + _errorMessage = result['message'] ?? 'Gagal mengecek status pembayaran'; + print('Gagal mengecek status pembayaran: $_errorMessage'); + } + + _isLoading = false; + notifyListeners(); + + return result; + } catch (e) { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + print('Error saat mengecek status pembayaran: $e'); + notifyListeners(); + + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Reset state + void reset() { + _isLoading = false; + _isPaymentInitiated = false; + _errorMessage = ''; + _paymentData = {}; + _redirectUrl = ''; + _snapToken = ''; + _paymentStatus = 'unpaid'; + _bookingId = null; + notifyListeners(); + } +} diff --git a/TA_android/lib/core/controllers/order_controller.dart b/TA_android/lib/core/controllers/order_controller.dart new file mode 100644 index 0000000..eef5cd5 --- /dev/null +++ b/TA_android/lib/core/controllers/order_controller.dart @@ -0,0 +1,38 @@ +import '../models/order_model.dart'; + +class OrderController { + // Sample data, in real app would come from API + final List orders = [ + OrderModel( + id: '001', + item: 'Kemeja Batik', + date: '12 Agustus 2023', + status: 'Selesai', + tailorName: 'Penjahit ABC', + price: 150000, + ), + OrderModel( + id: '002', + item: 'Celana Panjang', + date: '20 Agustus 2023', + status: 'Diproses', + tailorName: 'Penjahit XYZ', + price: 120000, + ), + OrderModel( + id: '003', + item: 'Jas Formal', + date: '1 September 2023', + status: 'Menunggu', + tailorName: 'Penjahit XYZ', + price: 450000, + ), + ]; + + // Method untuk mendapatkan pesanan berdasarkan status + List getOrdersByStatus(String status) { + if (status == 'Semua') { return orders; + } + return orders.where((order) => order.status == status).toList(); + } +} diff --git a/TA_android/lib/core/controllers/profile_controller.dart b/TA_android/lib/core/controllers/profile_controller.dart new file mode 100644 index 0000000..da7124e --- /dev/null +++ b/TA_android/lib/core/controllers/profile_controller.dart @@ -0,0 +1,566 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import '../services/api_service.dart'; +import '../providers/user_provider.dart'; +import 'package:provider/provider.dart'; +import '../models/gallery_item_model.dart'; +import '../utils/logger.dart'; +import '../services/profile_service.dart'; + +class ProfileController { + bool isLoading = false; + + // Memperbarui data pengguna dari respons JSON API + Future updateUserFromJson( + BuildContext context, Map userData) async { + try { + AppLogger.info('Memperbarui data pengguna dari JSON', + tag: 'ProfileController'); + + // Dapatkan UserProvider + final userProvider = Provider.of(context, listen: false); + + // Perbarui data pengguna menggunakan metode di UserProvider + await userProvider.updateUserFromJson(userData); + + AppLogger.info('Data pengguna berhasil diperbarui', + tag: 'ProfileController'); + return true; + } catch (e) { + AppLogger.error('Gagal memperbarui data pengguna dari JSON', + error: e, tag: 'ProfileController'); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text('Terjadi kesalahan saat memperbarui data pengguna: $e'), + backgroundColor: Colors.red, + ), + ); + } + return false; + } + } + + // Load user profile dari API + Future loadUserProfile(BuildContext context) async { + try { + isLoading = true; + AppLogger.info('Memuat profil pengguna', tag: 'ProfileController'); + + final result = await ProfileService.getProfile(); + + if (result['success'] && result['data'] != null) { + // Update UserProvider dengan data terbaru + final userProvider = Provider.of(context, listen: false); + await userProvider.updateUserFromJson(result['data']); + + AppLogger.info('Profil berhasil dimuat dan diperbarui', + tag: 'ProfileController'); + isLoading = false; + return true; + } else { + AppLogger.error('Gagal memuat profil: ${result['message']}', + tag: 'ProfileController'); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Gagal memuat profil'), + backgroundColor: Colors.red, + ), + ); + } + isLoading = false; + return false; + } + } catch (e) { + isLoading = false; + AppLogger.error('Exception saat memuat profil', + error: e, tag: 'ProfileController'); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + return false; + } + } + + // Upload foto profil + Future uploadProfilePhoto(BuildContext context, File photo) async { + isLoading = true; + AppLogger.info('Mulai upload foto profil', tag: 'ProfileController'); + + try { + // Menggunakan ProfileService daripada ApiService untuk upload foto + final result = await ProfileService.uploadProfilePhoto(photo); + + isLoading = false; + AppLogger.api('Respons upload foto profil:', + data: result, tag: 'ProfileController'); + + if (result['success']) { + // Update profile photo in UserProvider if data is returned + if (result.containsKey('data') && result['data'] != null) { + final userProvider = + Provider.of(context, listen: false); + if (userProvider.user != null) { + // Dapatkan URL foto dari respons API + String? photoUrl; + if (result['data'] is Map && result['data'].containsKey('photo')) { + photoUrl = result['data']['photo']; + AppLogger.debug('URL foto profil baru: $photoUrl', + tag: 'ProfileController'); + } + + // Update foto profil di UserProvider + if (photoUrl != null) { + await userProvider.updateUserPhoto(photoUrl); + AppLogger.info('Foto profil berhasil diperbarui di UserProvider', + tag: 'ProfileController'); + } + } + } + + // Memuat ulang profil lengkap setelah upload foto + await loadUserProfile(context); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + return true; + } else { + AppLogger.error('Gagal upload foto profil: ${result['message']}', + tag: 'ProfileController'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + return false; + } + } catch (e) { + isLoading = false; + AppLogger.error('Exception saat upload foto profil', + error: e, tag: 'ProfileController'); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + return false; + } + } + + // Upload foto galeri + Future uploadGalleryPhoto(BuildContext context, File photo, + {String title = '', + String description = '', + String category = 'umum'}) async { + isLoading = true; + AppLogger.info('Mulai upload foto galeri', tag: 'Gallery'); + + try { + // Gunakan API untuk upload foto galeri + AppLogger.debug('Mengirim file: ${photo.path} dengan judul: $title', + tag: 'Gallery'); + + final result = await ApiService.addTailorGalleryItem( + photo: photo, + title: title.isEmpty ? 'Karya Baru' : title, + description: + description.isEmpty ? 'Karya yang baru ditambahkan' : description, + category: category.isEmpty ? 'umum' : category, + ); + + isLoading = false; + AppLogger.api('Respons upload galeri', data: result, tag: 'Gallery'); + + if (result['success']) { + // Update gallery in UserProvider + final userProvider = Provider.of(context, listen: false); + if (userProvider.user != null) { + // Pastikan data dalam format yang benar + if (result['data'] != null) { + try { + // Buat objek GalleryItem dari respons + final galleryItem = GalleryItem.fromJson(result['data']); + + // Ambil URL foto dengan prioritas fullPhotoUrl jika tersedia + final photoUrl = galleryItem.fullPhotoUrl.isNotEmpty + ? galleryItem.fullPhotoUrl + : galleryItem.photo; + + AppLogger.debug('URL foto yang ditambahkan: $photoUrl', + tag: 'Gallery'); + + // Buat list galeri baru dengan foto yang baru ditambahkan + List currentGallery = + List.from(userProvider.user!.gallery ?? []); + + // Tambahkan URL baru jika belum ada dalam list + if (!currentGallery.contains(photoUrl) && photoUrl.isNotEmpty) { + currentGallery.add(photoUrl); + + // Update galeri di UserProvider + userProvider.updateUserGallery(currentGallery); + AppLogger.info( + 'Galeri berhasil diperbarui. Total: ${currentGallery.length} foto', + tag: 'Gallery'); + } else { + AppLogger.warning('Foto sudah ada dalam galeri atau URL kosong', + tag: 'Gallery'); + } + } catch (parseError) { + AppLogger.error('Error parsing data galeri', + error: parseError, tag: 'Gallery'); + AppLogger.debug('Data asli: ${result['data']}', tag: 'Gallery'); + } + } else { + AppLogger.warning('Data galeri kosong dari API', tag: 'Gallery'); + } + } + + // Memuat ulang profil lengkap setelah upload foto galeri + await loadUserProfile(context); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + result['message'] ?? 'Foto berhasil ditambahkan ke galeri'), + backgroundColor: Colors.green, + ), + ); + return true; + } else { + AppLogger.error('Gagal upload galeri: ${result['message']}', + tag: 'Gallery'); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text(result['message'] ?? 'Gagal menambahkan foto ke galeri'), + backgroundColor: Colors.red, + ), + ); + return false; + } + } catch (e) { + isLoading = false; + AppLogger.error('Exception saat upload galeri', error: e, tag: 'Gallery'); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal menambahkan foto galeri: $e'), + backgroundColor: Colors.red, + ), + ); + return false; + } + } + + // Hapus foto dari galeri + Future deleteGalleryPhoto(BuildContext context, String photoUrl, + {int? galleryId}) async { + isLoading = true; + AppLogger.info('Mulai hapus foto galeri: $photoUrl', tag: 'Gallery'); + + // Simpan referensi ke UserProvider di awal method + UserProvider? userProvider; + if (context.mounted) { + try { + userProvider = Provider.of(context, listen: false); + } catch (e) { + AppLogger.error('Tidak dapat mengakses UserProvider', + error: e, tag: 'Gallery'); + } + } + + try { + // Ekstrak ID dari URL foto jika tidak disediakan galleryId + int? photoId = galleryId; + if (photoId == null) { + photoId = extractPhotoIdFromUrl(photoUrl); + AppLogger.debug('ID diekstrak dari URL: $photoId', tag: 'Gallery'); + } + + if (photoId == null) { + AppLogger.error( + 'Tidak dapat mengidentifikasi ID galeri dari URL: $photoUrl', + tag: 'Gallery'); + + // Hanya tampilkan SnackBar jika context masih valid + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: + Text('Tidak dapat mengidentifikasi ID galeri dari URL foto'), + backgroundColor: Colors.red, + ), + ); + } + isLoading = false; + return false; + } + + // Gunakan API untuk menghapus foto galeri + AppLogger.debug('Menghapus foto dengan ID: $photoId dan URL: $photoUrl', + tag: 'Gallery'); + + final result = await ApiService.deleteTailorGalleryItem(photoId); + AppLogger.api('Respons hapus galeri', data: result, tag: 'Gallery'); + + isLoading = false; + + if (result['success']) { + // Update gallery in UserProvider jika tersedia + if (userProvider != null && userProvider.user != null) { + // Buat list galeri baru tanpa foto yang dihapus + List currentGallery = + List.from(userProvider.user!.gallery ?? []); + + AppLogger.debug( + 'Galeri sebelum dihapus: ${currentGallery.length} item', + tag: 'Gallery'); + + currentGallery.removeWhere((item) => item == photoUrl); + + AppLogger.debug( + 'Galeri setelah dihapus: ${currentGallery.length} item', + tag: 'Gallery'); + + // Update galeri di UserProvider + await userProvider.updateUserGallery(currentGallery); + AppLogger.info('Galeri berhasil diperbarui setelah penghapusan', + tag: 'Gallery'); + } else { + AppLogger.warning( + 'UserProvider atau user tidak tersedia, tidak dapat memperbarui galeri', + tag: 'Gallery'); + } + + // Memuat ulang profil lengkap setelah hapus foto galeri + await loadUserProfile(context); + + // Hanya tampilkan SnackBar jika context masih valid + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + result['message'] ?? 'Foto berhasil dihapus dari galeri'), + backgroundColor: Colors.green, + ), + ); + } + return true; + } else { + AppLogger.error('Gagal menghapus foto: ${result['message']}', + tag: 'Gallery'); + + // Cek apakah error terkait model tidak ditemukan + bool isNotFoundError = + result['message']?.toString().contains('No query results') ?? false; + + // Jika error adalah "record tidak ditemukan", hapus item dari UserProvider + if (isNotFoundError) { + AppLogger.warning( + 'Foto dengan ID $photoId tidak ditemukan di server, tapi akan dihapus dari UI', + tag: 'Gallery'); + + // Update galeri di UserProvider jika tersedia + if (userProvider != null && userProvider.user != null) { + List currentGallery = + List.from(userProvider.user!.gallery ?? []); + + currentGallery.removeWhere((item) => item == photoUrl); + await userProvider.updateUserGallery(currentGallery); + AppLogger.info( + 'Galeri diperbarui untuk menghapus item yang tidak ada di server', + tag: 'Gallery'); + + // Hanya tampilkan SnackBar jika context masih valid + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + 'Foto dihapus dari galeri lokal (tidak ada di server)'), + backgroundColor: Colors.orange, + ), + ); + } + return true; + } + } + + // Hanya tampilkan SnackBar jika context masih valid + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text(result['message'] ?? 'Gagal menghapus foto dari galeri'), + backgroundColor: Colors.red, + ), + ); + } + return false; + } + } catch (e) { + isLoading = false; + AppLogger.error('Exception saat menghapus foto', + error: e, tag: 'Gallery'); + + // Hanya tampilkan SnackBar jika context masih valid + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal menghapus foto galeri: $e'), + backgroundColor: Colors.red, + ), + ); + } + return false; + } + } + + // Fungsi pembantu untuk mengekstrak ID dari URL foto jika diperlukan + int? extractPhotoIdFromUrl(String url) { + try { + AppLogger.info('Mencoba ekstrak ID dari URL: $url', tag: 'Gallery'); + + // Log URL lengkap untuk debugging + if (url.isEmpty) { + AppLogger.error('URL kosong tidak dapat diekstrak', tag: 'Gallery'); + return null; + } + + // Coba beberapa pola URL yang mungkin + + // Pola 1: URL dengan format /storage/gallery/ID.jpg + RegExp regexStorage = RegExp(r'/storage/gallery/(\d+)\.(jpg|jpeg|png)'); + var matchStorage = regexStorage.firstMatch(url); + if (matchStorage != null && matchStorage.groupCount >= 1) { + int id = int.parse(matchStorage.group(1)!); + AppLogger.info('ID ditemukan dari pola storage: $id', tag: 'Gallery'); + return id; + } + + // Pola 2: URL dengan ID sebagai bagian terakhir path /gallery/ID + RegExp regexEndpoint = RegExp(r'/gallery/(\d+)(?:\.(jpg|jpeg|png))?'); + var matchEndpoint = regexEndpoint.firstMatch(url); + if (matchEndpoint != null && matchEndpoint.groupCount >= 1) { + int id = int.parse(matchEndpoint.group(1)!); + AppLogger.info('ID ditemukan dari pola endpoint: $id', tag: 'Gallery'); + return id; + } + + // Pola 3: URL dengan pattern /api/penjahit/gallery/ID + RegExp regexApiEndpoint = RegExp(r'/api/penjahit/gallery/(\d+)'); + var matchApiEndpoint = regexApiEndpoint.firstMatch(url); + if (matchApiEndpoint != null && matchApiEndpoint.groupCount >= 1) { + int id = int.parse(matchApiEndpoint.group(1)!); + AppLogger.info('ID ditemukan dari pola API endpoint: $id', + tag: 'Gallery'); + return id; + } + + // Pola 4: URL dengan ID sebelum ekstensi (namafile_ID.jpg) + RegExp regexFilename = RegExp(r'_(\d+)\.(jpg|jpeg|png)$'); + var matchFilename = regexFilename.firstMatch(url); + if (matchFilename != null && matchFilename.groupCount >= 1) { + int id = int.parse(matchFilename.group(1)!); + AppLogger.info('ID ditemukan dari pola filename: $id', tag: 'Gallery'); + return id; + } + + // Pola 5: Coba ekstrak angka terakhir dari URL sebagai fallback + RegExp regexLastNumber = RegExp(r'(\d+)(?:[^\d/]*)?$'); + var matchLastNumber = regexLastNumber.firstMatch(url); + if (matchLastNumber != null) { + int id = int.parse(matchLastNumber.group(1)!); + AppLogger.warning( + 'ID ditemukan dari angka terakhir (fallback): $id - ini mungkin tidak akurat!', + tag: 'Gallery'); + return id; + } + + // Jika tidak ada pola yang cocok, periksa jika ada parameter ID dalam URL (e.g. ?id=123) + RegExp regexQueryParam = RegExp(r'[?&]id=(\d+)'); + var matchQueryParam = regexQueryParam.firstMatch(url); + if (matchQueryParam != null && matchQueryParam.groupCount >= 1) { + int id = int.parse(matchQueryParam.group(1)!); + AppLogger.info('ID ditemukan dari query parameter: $id', + tag: 'Gallery'); + return id; + } + + AppLogger.error('Tidak dapat mengekstrak ID dari URL: $url', + tag: 'Gallery'); + return null; + } catch (e) { + AppLogger.error('Error saat mengekstrak photo ID', + error: e, tag: 'Gallery'); + return null; + } + } + + Future updateProfile( + BuildContext context, Map userData) async { + try { + AppLogger.info('Memulai proses update profil', tag: 'ProfileController'); + + final result = await ProfileService.updateProfile(userData); + + if (result['success']) { + // Update data di UserProvider + if (result['data'] != null) { + await updateUserFromJson(context, result['data']); + } + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Profil berhasil diperbarui'), + backgroundColor: Colors.green, + ), + ); + } + return true; + } else { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Gagal memperbarui profil'), + backgroundColor: Colors.red, + ), + ); + } + return false; + } + } catch (e) { + AppLogger.error('Exception saat update profil', + error: e, tag: 'ProfileController'); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + return false; + } + } +} diff --git a/TA_android/lib/core/controllers/wallet_wd_controller.dart b/TA_android/lib/core/controllers/wallet_wd_controller.dart new file mode 100644 index 0000000..060843a --- /dev/null +++ b/TA_android/lib/core/controllers/wallet_wd_controller.dart @@ -0,0 +1,345 @@ +import 'package:flutter/material.dart'; +import '../services/wallet_wd_service.dart'; +import '../models/wallet_model.dart'; +import 'dart:developer' as developer; + +class WalletWDController extends ChangeNotifier { + bool _isLoading = false; + String _errorMessage = ''; + WalletModel? _walletInfo; + List _bankAccounts = []; + List> _withdrawalHistory = []; + bool _isDisposed = false; + + // Debug info - tambahan untuk keperluan debugging + final Map _lastApiResponse = {}; + final bool _debugMode = true; + + // Getters + bool get isLoading => _isLoading; + String get errorMessage => _errorMessage; + WalletModel? get walletInfo => _walletInfo; + List get bankAccounts => _bankAccounts; + List> get withdrawalHistory => _withdrawalHistory; + Map get lastApiResponse => _lastApiResponse; // Getter untuk debug info + + // Helper method untuk safe notification + void _safeNotifyListeners() { + if (!_isDisposed) { + Future.microtask(() { + if (!_isDisposed) { + notifyListeners(); + } + }); + } + } + + // Helper method untuk set loading state + void _setLoading(bool value) { + _isLoading = value; + _safeNotifyListeners(); + } + + // Helper method untuk set error message + void _setError(String message) { + _errorMessage = message; + _safeNotifyListeners(); + } + + // Helper method untuk debugging + // ignore_for_file: avoid_print + void _logDebug(String message) { + if (_debugMode) { + developer.log('[WALLET_CONTROLLER] $message', name: 'TailorHub'); + print('[WALLET_CONTROLLER] $message'); + } + } + + @override + void dispose() { + _isDisposed = true; + super.dispose(); + } + + Future fetchWalletInfo() async { + if (_isLoading) return; + + _setLoading(true); + _setError(''); + + try { + _logDebug('Memanggil WalletWDService.getWalletInfo()'); + final result = await WalletWDService.getWalletInfo(); + + // Simpan respons untuk debugging + _lastApiResponse['getWalletInfo'] = result; + _logDebug('Hasil getWalletInfo: ${result['success']}'); + + if (result['success']) { + _walletInfo = WalletModel.fromJson(result['data']); + _logDebug('WalletInfo berhasil dimuat. Balance: ${_walletInfo?.balance}'); + } else { + _setError(result['message']); + _logDebug('Error getWalletInfo: ${result['message']}'); + } + } catch (e) { + _logDebug('Exception getWalletInfo: $e'); + _setError('Terjadi kesalahan: $e'); + } finally { + _setLoading(false); + } + } + + Future fetchBankAccounts() async { + if (_isLoading) return; + + _setLoading(true); + _setError(''); + + try { + _logDebug('Memanggil WalletWDService.getBankAccounts()'); + final result = await WalletWDService.getBankAccounts(); + + // Simpan respons untuk debugging + _lastApiResponse['getBankAccounts'] = result; + _logDebug('Hasil getBankAccounts: ${result['success']}'); + + if (result['success']) { + _bankAccounts = (result['data'] as List) + .map((json) => BankAccount.fromJson(json)) + .toList(); + _logDebug('BankAccounts berhasil dimuat. Jumlah: ${_bankAccounts.length}'); + } else { + _setError(result['message']); + _logDebug('Error getBankAccounts: ${result['message']}'); + } + } catch (e) { + _logDebug('Exception getBankAccounts: $e'); + _setError('Terjadi kesalahan: $e'); + } finally { + _setLoading(false); + } + } + + Future> registerBankAccount({ + required String bankName, + required String accountNumber, + required String accountHolderName, + }) async { + if (_isLoading) { + return {'success': false, 'message': 'Proses sedang berlangsung'}; + } + + _setLoading(true); + _setError(''); + + try { + _logDebug('Memanggil WalletWDService.registerBankAccount()'); + final result = await WalletWDService.registerBankAccount( + bankName: bankName, + accountNumber: accountNumber, + accountHolderName: accountHolderName, + ); + + // Simpan respons untuk debugging + _lastApiResponse['registerBankAccount'] = result; + _logDebug('Hasil registerBankAccount: ${result['success']}'); + + if (result['success']) { + await fetchBankAccounts(); + _logDebug('registerBankAccount berhasil: ${result['message']}'); + } else { + _setError(result['message']); + _logDebug('Error registerBankAccount: ${result['message']}'); + } + return result; + } catch (e) { + _logDebug('Exception registerBankAccount: $e'); + _setError('Terjadi kesalahan: $e'); + return { + 'success': false, + 'message': _errorMessage, + }; + } finally { + _setLoading(false); + } + } + + Future> requestWithdrawal({ + required int bankAccountId, + required double amount, + }) async { + if (_isLoading) { + return {'success': false, 'message': 'Proses sedang berlangsung'}; + } + + _setLoading(true); + _setError(''); + + try { + _logDebug('Memanggil WalletWDService.requestWithdrawal()'); + final result = await WalletWDService.requestWithdrawal( + bankAccountId: bankAccountId, + amount: amount, + ); + + // Simpan respons untuk debugging + _lastApiResponse['requestWithdrawal'] = result; + _logDebug('Hasil requestWithdrawal: ${result['success']}'); + + if (result['success']) { + // Update wallet info dari respons API jika tersedia + if (result['data'] != null && result['data']['wallet'] != null) { + _logDebug('Update wallet info dari respons API: ${result['data']['wallet']}'); + updateWalletInfoFromApiResponse(result['data']['wallet']); + + // Tambahkan entry penarikan baru ke riwayat penarikan + if (result['data']['withdrawal'] != null) { + _withdrawalHistory.insert(0, result['data']['withdrawal']); + _logDebug('Added new withdrawal to history: ${result['data']['withdrawal']}'); + } + } else { + // Jika data wallet tidak tersedia dalam respons, ambil dari API + await Future.wait([ + fetchWalletInfo(), + fetchWithdrawalHistory(), + ]); + } + + _logDebug('requestWithdrawal berhasil: ${result['message']}'); + } else { + // Jika gagal namun ada info wallet baru, update juga + if (result['wallet_info'] != null) { + updateWalletInfoFromApiResponse(result['wallet_info']); + } + + _setError(result['message']); + _logDebug('Error requestWithdrawal: ${result['message']}'); + } + return result; + } catch (e) { + _logDebug('Exception requestWithdrawal: $e'); + _setError('Terjadi kesalahan: $e'); + return { + 'success': false, + 'message': _errorMessage, + }; + } finally { + _setLoading(false); + } + } + + Future fetchWithdrawalHistory({String? status}) async { + if (_isLoading) return; + + _setLoading(true); + _setError(''); + + try { + _logDebug('Memanggil WalletWDService.getWithdrawalHistory(status: $status)'); + final result = await WalletWDService.getWithdrawalHistory(status: status); + + // Simpan respons untuk debugging + _lastApiResponse['getWithdrawalHistory'] = result; + _logDebug('Hasil getWithdrawalHistory: ${result['success']}'); + + if (result['success']) { + _withdrawalHistory = List>.from(result['data']); + _logDebug('WithdrawalHistory berhasil dimuat. Jumlah: ${_withdrawalHistory.length}'); + + // Log detail data untuk debugging + if (_debugMode) { + _logDebug('Detail data withdrawal:'); + _logDebug('Raw response: ${result['data']}'); + + if (_withdrawalHistory.isEmpty) { + _logDebug('Data withdrawal kosong!'); + } else { + for (int i = 0; i < _withdrawalHistory.length; i++) { + _logDebug('Withdrawal #${i+1}: ${_withdrawalHistory[i]}'); + } + } + } + } else { + _setError(result['message']); + _logDebug('Error getWithdrawalHistory: ${result['message']}'); + } + } catch (e, stackTrace) { + _logDebug('Exception getWithdrawalHistory: $e'); + _logDebug('StackTrace: $stackTrace'); + _setError('Terjadi kesalahan: $e'); + } finally { + _setLoading(false); + } + } + + // Helper method untuk mendapatkan status text penarikan + String getWithdrawalStatusText(String status) { + switch (status.toLowerCase()) { + case 'pending': + return 'Menunggu Proses'; + case 'processing': + return 'Sedang Diproses'; + case 'completed': + return 'Selesai'; + case 'rejected': + return 'Ditolak'; + default: + return 'Status Tidak Diketahui'; + } + } + + // Helper method untuk mendapatkan warna status penarikan + Color getWithdrawalStatusColor(String status) { + switch (status.toLowerCase()) { + case 'pending': + return const Color(0xFFFFA000); // Orange + case 'processing': + return const Color(0xFF1976D2); // Biru + case 'completed': + return const Color(0xFF34A853); // Hijau + case 'rejected': + return const Color(0xFFEA4335); // Merah + default: + return const Color(0xFF9AA0A6); // Abu-abu + } + } + + // Reset state + void reset() { + _setLoading(false); + _setError(''); + _walletInfo = null; + _bankAccounts = []; + _withdrawalHistory = []; + _safeNotifyListeners(); + } + + // Method untuk pengujian - cek koneksi + Future testConnection() async { + try { + _logDebug('Testing connection to wallet API'); + final result = await WalletWDService.getWalletInfo(); + _lastApiResponse['testConnection'] = result; + _logDebug('Test koneksi: ${result['success']}'); + return result['success']; + } catch (e) { + _logDebug('Test koneksi gagal: $e'); + return false; + } + } + + // Metode untuk mengupdate wallet info dari respons API + void updateWalletInfoFromApiResponse(Map walletData) { + try { + _logDebug('Updating wallet info from API response: $walletData'); + + // Perbarui wallet info dari data API + _walletInfo = WalletModel.fromJson(walletData); + _logDebug('Wallet info updated: balance=${_walletInfo?.balance}, pending=${_walletInfo?.pendingWithdrawals}, available=${_walletInfo?.availableBalance}'); + _safeNotifyListeners(); + } catch (e) { + _logDebug('Error updating wallet info: $e'); + } + } +} diff --git a/TA_android/lib/core/models/booking_model.dart b/TA_android/lib/core/models/booking_model.dart new file mode 100644 index 0000000..5839ef4 --- /dev/null +++ b/TA_android/lib/core/models/booking_model.dart @@ -0,0 +1,536 @@ +import '../services/api_service.dart'; +// ignore_for_file: avoid_print + +class BookingModel { + final int id; + final String? transactionCode; + final int? customerId; + final int? tailorId; + final String appointmentDate; + final String appointmentTime; + final String serviceType; + final String category; + final String? designPhoto; + final String? image; + final String? notes; + final String status; + final String? totalPrice; + final String? paymentMethod; + final String? paymentStatus; + final String? measurements; + final String? repairDetails; + final String? repairPhoto; + final String? repairNotes; + final String? completionPhoto; + final String? completionNotes; + final String? completionDate; + final String? acceptedAt; + final String? rejectedAt; + final String? completedAt; + final String? pickupDate; + final String? rejectionReason; + final String createdAt; + final String updatedAt; + final Map? customer; + final Map? tailor; + final dynamic rating; + final String? review; + final String? ratingDate; + final String? tailorName; + final String? tailorImage; + final String? customerName; + final String? customerImage; + final String? customerPhone; + final String? customerEmail; + final String? customerAddress; + final String? tailorPhone; + final String? tailorEmail; + final String? tailorAddress; + final String? price; + + String get statusDetail => getStatusText(); + + BookingModel({ + required this.id, + this.transactionCode, + this.customerId, + this.tailorId, + required this.appointmentDate, + required this.appointmentTime, + required this.serviceType, + required this.category, + this.designPhoto, + this.image, + this.notes, + required this.status, + this.totalPrice, + this.paymentMethod, + this.paymentStatus, + this.measurements, + this.repairDetails, + this.repairPhoto, + this.repairNotes, + this.completionPhoto, + this.completionNotes, + this.completionDate, + this.acceptedAt, + this.rejectedAt, + this.completedAt, + this.pickupDate, + this.rejectionReason, + required this.createdAt, + required this.updatedAt, + this.customer, + this.tailor, + this.rating, + this.review, + this.ratingDate, + this.tailorName, + this.tailorImage, + this.customerName, + this.customerImage, + this.customerPhone, + this.customerEmail, + this.customerAddress, + this.tailorPhone, + this.tailorEmail, + this.tailorAddress, + this.price, + }); + + factory BookingModel.fromJson(Map json) { + try { + // Jika ada measurements, konversi ke string + String? measurementsStr; + if (json['measurements'] != null) { + if (json['measurements'] is String) { + measurementsStr = json['measurements']; + } else { + measurementsStr = json['measurements'].toString(); + } + } + + // Jika ada repair_details, konversi ke string + String? repairDetailsStr; + if (json['repair_details'] != null) { + if (json['repair_details'] is String) { + repairDetailsStr = json['repair_details']; + } else { + repairDetailsStr = json['repair_details'].toString(); + } + } + + // Jika ada tailor, konversi ke Map + Map? tailorData; + if (json['tailor'] != null) { + if (json['tailor'] is Map) { + tailorData = Map.from(json['tailor']); + } + } + + return BookingModel( + id: json['id'] ?? 0, + transactionCode: json['transaction_code'], + customerId: json['customer_id'], + tailorId: json['tailor_id'], + appointmentDate: json['appointment_date'] ?? '', + appointmentTime: json['appointment_time'] ?? '', + serviceType: json['service_type'] ?? 'Jahit Baru', + category: json['category'] ?? 'Atasan', + designPhoto: json['design_photo'], + image: json['image'], + notes: json['notes'] ?? '', + status: json['status'] ?? 'reservasi', + totalPrice: json['total_price']?.toString(), + paymentMethod: json['payment_method'], + paymentStatus: json['payment_status'], + measurements: measurementsStr, + repairDetails: repairDetailsStr, + repairPhoto: json['repair_photo'], + repairNotes: json['repair_notes'], + completionPhoto: json['completion_photo'], + completionNotes: json['completion_notes'], + completionDate: json['completion_date'], + acceptedAt: json['accepted_at'], + rejectedAt: json['rejected_at'], + completedAt: json['completed_at'], + pickupDate: json['pickup_date'], + rejectionReason: json['rejection_reason'], + createdAt: json['created_at'] ?? DateTime.now().toIso8601String(), + updatedAt: json['updated_at'] ?? DateTime.now().toIso8601String(), + customer: json['customer'], + tailor: tailorData, + rating: json['rating'], + review: json['review'], + ratingDate: json['rating_date'], + tailorName: json['tailor_name'] ?? json['tailor']?['name'], + tailorImage: json['tailor_image'] ?? json['tailor']?['image'], + customerName: json['customer_name'] ?? json['customer']?['name'], + customerImage: json['customer_image'] ?? json['customer']?['image'], + customerPhone: json['customer_phone'], + customerEmail: json['customer_email'], + customerAddress: json['customer_address'], + tailorPhone: json['tailor_phone'], + tailorEmail: json['tailor_email'], + tailorAddress: json['tailor_address'], + price: json['price']?.toString(), + ); + } catch (e, stackTrace) { + print('ERROR: Failed to parse booking JSON: $e'); + print('ERROR: Stack trace: $stackTrace'); + print('ERROR: JSON data: $json'); + rethrow; + } + } + + Map toMap() { + return { + 'id': id, + 'transaction_code': transactionCode, + 'customer_id': customerId, + 'tailor_id': tailorId, + 'appointment_date': appointmentDate, + 'appointment_time': appointmentTime, + 'service_type': serviceType, + 'category': category, + 'status': status, + 'statusDetail': statusDetail, + 'totalPrice': totalPrice, + 'paymentStatus': paymentStatus, + 'rating': rating, + 'review': review, + 'designPhoto': designPhoto, + 'notes': notes, + 'created_at': createdAt, + 'updated_at': updatedAt, + 'payment_method': paymentMethod, + 'price': price, + }; + } + + String getStatusText() { + switch (status.toLowerCase()) { + case 'reservasi': + return 'Menunggu konfirmasi dari penjahit'; + case 'diproses': + return 'Sedang dikerjakan oleh penjahit'; + case 'selesai': + return 'Pesanan telah selesai'; + case 'dibatalkan': + return 'Pesanan dibatalkan: ${rejectionReason ?? "Tidak ada alasan"}'; + default: + return 'Status tidak diketahui'; + } + } + + // Mendapatkan nama pelanggan + String getCustomerName() { + return customerName ?? customer?['name'] ?? 'Pelanggan'; + } + + // Mendapatkan nama penjahit + String getTailorName() { + return tailorName ?? tailor?['name'] ?? 'Penjahit'; + } + + // Mendapatkan foto profil penjahit + String? getTailorPhoto() { + // Debug informasi + print('DEBUG: Getting tailor photo'); + print('DEBUG: Tailor object: $tailor'); + + // Cek dari objek tailor + if (tailor != null && + tailor!.containsKey('profile_photo') && + tailor!['profile_photo'] != null && + tailor!['profile_photo'].toString().isNotEmpty) { + String photo = tailor!['profile_photo'].toString(); + print('DEBUG: Found profile_photo in tailor object: $photo'); + return photo; + } + + // Cek field tailor_photo dari objek tailor (alternativ nama) + if (tailor != null && tailor!.containsKey('tailor_photo')) { + String? photo = tailor!['tailor_photo']?.toString(); + if (photo != null && photo.isNotEmpty) { + print('DEBUG: Found tailor_photo in booking: $photo'); + return photo; + } + } + + print('DEBUG: No tailor photo found'); + return null; + } + + // Mendapatkan foto profil pelanggan atau penjahit (tergantung konteks) + String? getProfilePhoto() { + // Dalam konteks customer app, kita prioritaskan foto penjahit + String? photo = getTailorPhoto(); + if (photo != null) { + print('DEBUG: Using tailor photo as profile photo: $photo'); + return photo; + } + + // Fallback ke foto customer jika tidak ada foto penjahit + photo = getCustomerPhoto(); + if (photo != null) { + print('DEBUG: Using customer photo as profile photo: $photo'); + return photo; + } + + print('DEBUG: No profile photo found'); + return null; + } + + // Mendapatkan foto profil pelanggan + String? getCustomerPhoto() { + // Debug informasi + print('DEBUG: Customer object in BookingModel: $customer'); + + // Cek foto di objek customer + if (customer != null && + customer!.containsKey('profile_photo') && + customer!['profile_photo'] != null && + customer!['profile_photo'].toString().isNotEmpty) { + print( + 'DEBUG: Found profile_photo in customer object: ${customer!['profile_photo']}'); + return customer!['profile_photo']; + } + + // Periksa jika ada objek tailor dalam booking + if (customer != null && + customer!.containsKey('tailor') && + customer!['tailor'] != null && + customer!['tailor'] is Map) { + final tailor = customer!['tailor'] as Map; + if (tailor.containsKey('profile_photo') && + tailor['profile_photo'] != null && + tailor['profile_photo'].toString().isNotEmpty) { + print( + 'DEBUG: Found profile_photo in tailor object: ${tailor['profile_photo']}'); + return tailor['profile_photo']; + } + } + + print('DEBUG: No profile photo found in booking data'); + return null; + } + + // Mendapatkan warna untuk status + String getStatusColor() { + switch (status.toLowerCase()) { + case 'reservasi': + return '#FFA726'; // Orange + case 'accepted': + return '#4CAF50'; // Green + case 'rejected': + return '#F44336'; // Red + case 'in_progress': + return '#2196F3'; // Blue + case 'completed': + return '#8BC34A'; // Light Green + case 'delivered': + return '#9C27B0'; // Purple + default: + return '#757575'; // Grey + } + } + + // Format tanggal dengan format yang lebih user-friendly + String getFormattedDate() { + try { + print( + 'DEBUG: Getting formatted date for appointmentDate: $appointmentDate'); + + if (appointmentDate.isEmpty) { + print('DEBUG: appointmentDate is empty'); + return 'Belum ditentukan'; + } + + // Jika sudah dalam format yang benar (contoh: "26 April 2024") + if (appointmentDate.contains(' ') && + !appointmentDate.contains('-') && + !appointmentDate.contains('T')) { + print('DEBUG: Date is already in correct format: $appointmentDate'); + return appointmentDate; + } + + DateTime date; + try { + // Coba parse format ISO dengan timezone (2024-04-26T00:00:00.000000Z) + if (appointmentDate.contains('T')) { + date = DateTime.parse(appointmentDate); + print('DEBUG: Successfully parsed ISO date with timezone: $date'); + } + // Coba parse format tanggal sederhana (2024-04-26) + else if (appointmentDate.contains('-')) { + final parts = appointmentDate.split('-'); + if (parts.length == 3) { + date = DateTime( + int.parse(parts[0]), int.parse(parts[1]), int.parse(parts[2])); + print('DEBUG: Successfully parsed simple date: $date'); + } else { + print('ERROR: Invalid date parts length: ${parts.length}'); + return 'Belum ditentukan'; + } + } + // Format tidak dikenal + else { + print('ERROR: Unknown date format: $appointmentDate'); + return 'Belum ditentukan'; + } + + // Format ke bahasa Indonesia + List months = [ + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember' + ]; + + String formattedDate = + '${date.day} ${months[date.month - 1]} ${date.year}'; + print('DEBUG: Successfully formatted date: $formattedDate'); + return formattedDate; + } catch (parseError) { + print( + 'ERROR: Failed to parse date: $parseError for date: $appointmentDate'); + return 'Belum ditentukan'; + } + } catch (e, stackTrace) { + print('ERROR: Exception in getFormattedDate: $e'); + print('ERROR: Stack trace: $stackTrace'); + print('ERROR: Original appointmentDate: $appointmentDate'); + return 'Belum ditentukan'; + } + } + + // Format waktu dengan format yang lebih user-friendly + String getFormattedTime() { + try { + print( + 'DEBUG: Getting formatted time for appointmentTime: $appointmentTime'); + + if (appointmentTime.isEmpty) { + print('DEBUG: appointmentTime is empty'); + return '-'; + } + + // Cek jika format sudah H:i + if (appointmentTime.contains(':')) { + final parts = appointmentTime.split(':'); + if (parts.length >= 2) { + final hour = int.parse(parts[0]); + // Ambil menit saja tanpa detik jika ada + String minutePart = parts[1]; + if (minutePart.contains(' ')) { + minutePart = minutePart.split(' ')[0]; + } + final minute = int.parse(minutePart); + + // Format 24 jam + String formattedTime = + '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')} WIB'; + print('DEBUG: Successfully formatted time: $formattedTime'); + return formattedTime; + } + } + + // Default fallback + print('DEBUG: Using default time format: $appointmentTime WIB'); + return '$appointmentTime WIB'; + } catch (e) { + print('ERROR: Failed to format time: $e for time: $appointmentTime'); + return appointmentTime; + } + } + + // Mendapatkan data lengkap untuk detail order + Map getOrderDetails() { + return { + 'id': id, + 'customer_id': customerId, + 'tailor_id': tailorId, + 'appointmentDate': appointmentDate, + 'appointmentTime': appointmentTime, + 'serviceType': serviceType, + 'category': category, + 'designPhoto': designPhoto, + 'image': image, + 'notes': notes, + 'status': status, + 'statusDetail': statusDetail, + 'total_price': totalPrice, + 'payment_status': paymentStatus, + 'payment_method': paymentMethod, + 'transaction_code': transactionCode, + 'measurements': measurements, + 'repair_details': repairDetails, + 'repair_photo': repairPhoto, + 'repair_notes': repairNotes, + 'completion_photo': completionPhoto, + 'completion_notes': completionNotes, + 'completion_date': completionDate, + 'accepted_at': acceptedAt, + 'rejected_at': rejectedAt, + 'completed_at': completedAt, + 'pickup_date': pickupDate, + 'rejection_reason': rejectionReason, + 'created_at': createdAt, + 'updated_at': updatedAt, + 'customer': customer, + 'tailor': tailor, + 'rating': rating, + 'review': review, + 'rating_date': ratingDate, + 'tailorName': getTailorName(), + 'tailorImage': getTailorPhoto(), + 'customerName': getCustomerName(), + 'customerImage': getProfilePhoto(), + 'customerPhone': customerPhone, + 'customerEmail': customerEmail, + 'customerAddress': customerAddress, + 'tailorPhone': tailorPhone, + 'tailorEmail': tailorEmail, + 'tailorAddress': tailorAddress, + 'price': price, + }; + } + + // Helper untuk format tanggal untuk tampilan + String _formatDateForDisplay(String dateString) { + try { + DateTime date = DateTime.parse(dateString); + return "${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}"; + } catch (e) { + print('ERROR: Gagal memformat tanggal: $dateString, error: $e'); + return dateString; + } + } + + // Mendapatkan URL lengkap untuk foto desain + Future getFullDesignPhotoUrl() async { + if (designPhoto == null || designPhoto!.isEmpty) { + print('DEBUG BOOKING: Design photo is null or empty'); + return null; + } + + try { + // Gunakan fungsi khusus untuk memperbaiki URL foto desain + final fixedUrl = await ApiService.fixDesignPhotoUrl(designPhoto!); + print('DEBUG BOOKING: Fixed design photo URL: $fixedUrl'); + return fixedUrl; + } catch (e) { + print('ERROR BOOKING: Failed to fix design photo URL: $e'); + return designPhoto; + } + } +} diff --git a/TA_android/lib/core/models/gallery_item_model.dart b/TA_android/lib/core/models/gallery_item_model.dart new file mode 100644 index 0000000..68b5e30 --- /dev/null +++ b/TA_android/lib/core/models/gallery_item_model.dart @@ -0,0 +1,47 @@ +class GalleryItem { + final int id; + final String title; + final String description; + final String category; + final String photo; + final String fullPhotoUrl; + final String createdAt; + final String updatedAt; + + GalleryItem({ + required this.id, + required this.title, + required this.description, + required this.category, + required this.photo, + required this.fullPhotoUrl, + required this.createdAt, + required this.updatedAt, + }); + + factory GalleryItem.fromJson(Map json) { + return GalleryItem( + id: json['id'] ?? 0, + title: json['title'] ?? '', + description: json['description'] ?? '', + category: json['category'] ?? '', + photo: json['photo'] ?? '', + fullPhotoUrl: json['full_photo_url'] ?? json['photo'] ?? '', + createdAt: json['created_at'] ?? '', + updatedAt: json['updated_at'] ?? '', + ); + } + + Map toJson() { + return { + 'id': id, + 'title': title, + 'description': description, + 'category': category, + 'photo': photo, + 'full_photo_url': fullPhotoUrl, + 'created_at': createdAt, + 'updated_at': updatedAt, + }; + } +} diff --git a/TA_android/lib/core/models/gallery_model.dart b/TA_android/lib/core/models/gallery_model.dart new file mode 100644 index 0000000..04d5bc3 --- /dev/null +++ b/TA_android/lib/core/models/gallery_model.dart @@ -0,0 +1,37 @@ +class GalleryModel { + final int id; + final int userId; + final String photo; + final String title; + final String description; + final String category; + final DateTime createdAt; + final DateTime updatedAt; + final String? fullPhotoUrl; + + GalleryModel({ + required this.id, + required this.userId, + required this.photo, + required this.title, + required this.description, + required this.category, + required this.createdAt, + required this.updatedAt, + this.fullPhotoUrl, + }); + + factory GalleryModel.fromJson(Map json) { + return GalleryModel( + id: json['id'], + userId: json['user_id'], + photo: json['photo'], + title: json['title'] ?? '', + description: json['description'] ?? '', + category: json['category'] ?? '', + createdAt: DateTime.parse(json['created_at']), + updatedAt: DateTime.parse(json['updated_at']), + fullPhotoUrl: json['full_photo_url'], + ); + } +} diff --git a/TA_android/lib/core/models/order_model.dart b/TA_android/lib/core/models/order_model.dart new file mode 100644 index 0000000..e3dc7a7 --- /dev/null +++ b/TA_android/lib/core/models/order_model.dart @@ -0,0 +1,17 @@ +class OrderModel { + final String id; + final String item; + final String date; + final String status; + final String tailorName; + final double price; + + OrderModel({ + required this.id, + required this.item, + required this.date, + required this.status, + required this.tailorName, + required this.price, + }); +} diff --git a/TA_android/lib/core/models/review_model.dart b/TA_android/lib/core/models/review_model.dart new file mode 100644 index 0000000..060cf0b --- /dev/null +++ b/TA_android/lib/core/models/review_model.dart @@ -0,0 +1,54 @@ +class CustomerReview { + final String? name; + final String? profilePhoto; + + CustomerReview({this.name, this.profilePhoto}); + + factory CustomerReview.fromJson(Map json) { + return CustomerReview( + name: json['name'], + profilePhoto: json['profile_photo'], + ); + } + + Map toJson() { + return { + 'name': name, + 'profile_photo': profilePhoto, + }; + } +} + +class RatingModel { + final String rating; + final String review; + final String createdAt; + final CustomerReview? customer; + + RatingModel({ + required this.rating, + required this.review, + required this.createdAt, + this.customer, + }); + + factory RatingModel.fromJson(Map json) { + return RatingModel( + rating: json['rating'].toString(), + review: json['review'] ?? '', + createdAt: json['created_at'] ?? '', + customer: json['customer'] != null + ? CustomerReview.fromJson(json['customer']) + : null, + ); + } + + Map toJson() { + return { + 'rating': rating, + 'review': review, + 'created_at': createdAt, + 'customer': customer?.toJson(), + }; + } +} \ No newline at end of file diff --git a/TA_android/lib/core/models/specialization_model.dart b/TA_android/lib/core/models/specialization_model.dart new file mode 100644 index 0000000..f3c3a7f --- /dev/null +++ b/TA_android/lib/core/models/specialization_model.dart @@ -0,0 +1,96 @@ +class SpecializationModel { + final int? id; + final String name; + final String? category; + final String? photo; + final String? fullPhotoUrl; + bool isSelected; + + SpecializationModel({ + this.id, + required this.name, + this.category, + this.photo, + this.fullPhotoUrl, + this.isSelected = false, + }); + + // Create a copy of the model with updated selection state + // ignore_for_file: avoid_print + SpecializationModel copyWith({ + int? id, + String? name, + String? category, + String? photo, + String? fullPhotoUrl, + bool? isSelected, + }) { + return SpecializationModel( + id: id ?? this.id, + name: name ?? this.name, + category: category ?? this.category, + photo: photo ?? this.photo, + fullPhotoUrl: fullPhotoUrl ?? this.fullPhotoUrl, + isSelected: isSelected ?? this.isSelected, + ); + } + + // Factory constructor to create a SpecializationModel from JSON + factory SpecializationModel.fromJson(Map json) { + return SpecializationModel( + id: json['id'] as int?, + name: json['name'] as String, + category: json['category'] as String?, + photo: json['photo'] as String?, + fullPhotoUrl: json['full_photo_url'] as String?, + ); + } + + // Convert the model to JSON + Map toJson() { + return { + 'id': id, + 'name': name, + 'category': category, + 'photo': photo, + 'full_photo_url': fullPhotoUrl, + 'is_selected': isSelected, + }; + } + + // Get the image path - returns fullPhotoUrl if available, otherwise returns default image + String get imagePath { + // Debug logging + print('=== SpecializationModel Debug Info ==='); + print('Name: $name'); + print('Photo: $photo'); + print('FullPhotoUrl: $fullPhotoUrl'); + print('Is Network Image: $isNetworkImage'); + print('Selected: $isSelected'); + print('============================='); + + if (fullPhotoUrl != null && fullPhotoUrl!.isNotEmpty) { + return fullPhotoUrl!; + } + if (photo != null && photo!.isNotEmpty) { + return photo!; + } + return 'assets/images/tailor_default.png'; + } + + // Check if the image is from network + bool get isNetworkImage { + if (fullPhotoUrl != null && fullPhotoUrl!.isNotEmpty) { + return fullPhotoUrl!.startsWith('http'); + } + if (photo != null && photo!.isNotEmpty) { + return photo!.startsWith('http'); + } + return false; + } + + @override + String toString() { + return 'SpecializationModel(id: $id, name: $name, category: $category, isSelected: $isSelected)'; + } +} diff --git a/TA_android/lib/core/models/tailor_model.dart b/TA_android/lib/core/models/tailor_model.dart new file mode 100644 index 0000000..890328e --- /dev/null +++ b/TA_android/lib/core/models/tailor_model.dart @@ -0,0 +1,271 @@ +import '../services/api_service.dart'; +import 'review_model.dart'; + +class SpecializationModel { + final int id; + final String name; + final String category; + final String? icon; + final String? photo; + final DateTime? createdAt; + final DateTime? updatedAt; + + SpecializationModel({ + required this.id, + required this.name, + required this.category, + this.icon, + this.photo, + this.createdAt, + this.updatedAt, + }); + + factory SpecializationModel.fromJson(Map json) { + return SpecializationModel( + id: json['id'], + name: json['name'], + category: json['category'], + icon: json['icon'], + photo: json['photo'], + createdAt: json['created_at'] != null + ? DateTime.parse(json['created_at']) + : null, + updatedAt: json['updated_at'] != null + ? DateTime.parse(json['updated_at']) + : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'category': category, + 'icon': icon, + 'photo': photo, + 'created_at': createdAt?.toIso8601String(), + 'updated_at': updatedAt?.toIso8601String(), + }; + } +} + +class TailorModel { + final int id; + final String name; + final String email; + final String role; + final String phoneNumber; + final String address; + final String? shopDescription; + final String? profilePhoto; + final List gallery; + final int totalOrders; + final DateTime createdAt; + final DateTime updatedAt; + final List specializations; + final double? average_rating; + final int? completed_orders; + final String? latitude; + final String? longitude; + double? distance; + final List ratings; + + TailorModel({ + required this.id, + required this.name, + required this.email, + required this.role, + required this.phoneNumber, + required this.address, + this.shopDescription, + this.profilePhoto, + required this.gallery, + required this.totalOrders, + required this.createdAt, + required this.updatedAt, + required this.specializations, + this.average_rating, + this.completed_orders, + this.latitude, + this.longitude, + this.distance, + this.ratings = const [], + }); + + factory TailorModel.fromJson(Map json) { + var avgRating = 0.0; + var completedOrders = 0; + + // Cek apakah ada rating_info dalam respons + if (json['rating_info'] != null && json['rating_info'] is Map) { + var ratingInfo = json['rating_info'] as Map; + + // Ambil average_rating dari rating_info + if (ratingInfo.containsKey('average_rating')) { + if (ratingInfo['average_rating'] is int) { + avgRating = (ratingInfo['average_rating'] as int).toDouble(); + } else if (ratingInfo['average_rating'] is double) { + avgRating = ratingInfo['average_rating']; + } else if (ratingInfo['average_rating'] is String) { + avgRating = double.tryParse(ratingInfo['average_rating']) ?? 0.0; + } + } + + // Ambil total_reviews dari rating_info sebagai completed_orders + if (ratingInfo.containsKey('total_reviews')) { + if (ratingInfo['total_reviews'] is int) { + completedOrders = ratingInfo['total_reviews']; + } else if (ratingInfo['total_reviews'] is String) { + completedOrders = int.tryParse(ratingInfo['total_reviews']) ?? 0; + } + } + } else { + // Jika tidak ada rating_info, coba ambil dari field average_rating langsung (fallback) + if (json['average_rating'] != null) { + if (json['average_rating'] is int) { + avgRating = (json['average_rating'] as int).toDouble(); + } else if (json['average_rating'] is double) { + avgRating = json['average_rating']; + } else if (json['average_rating'] is String) { + avgRating = double.tryParse(json['average_rating']) ?? 0.0; + } + } + + // Ambil completed_orders langsung jika tersedia + if (json['completed_orders'] != null) { + if (json['completed_orders'] is int) { + completedOrders = json['completed_orders']; + } else if (json['completed_orders'] is String) { + completedOrders = int.tryParse(json['completed_orders']) ?? 0; + } + } + } + + // Debug log untuk rating dan review + // ignore_for_file: avoid_print + print('DEBUG TailorModel: Parsing tailor ID ${json['id']} - Name: ${json['name']}'); + print('DEBUG TailorModel: Rating info present: ${json['rating_info'] != null}'); + if (json['rating_info'] != null) { + print('DEBUG TailorModel: Rating info content: ${json['rating_info']}'); + } + print('DEBUG TailorModel: Final average_rating: $avgRating'); + print('DEBUG TailorModel: Final completed_orders/reviews: $completedOrders'); + + return TailorModel( + id: json['id'], + name: json['name'], + email: json['email'], + role: json['role'], + phoneNumber: json['phone_number'], + address: json['address'], + shopDescription: json['shop_description'], + profilePhoto: json['profile_photo'], + gallery: json['gallery'] ?? [], + totalOrders: json['total_orders'] ?? 0, + createdAt: DateTime.parse(json['created_at']), + updatedAt: DateTime.parse(json['updated_at']), + specializations: json['specializations'] ?? [], + average_rating: avgRating, + completed_orders: completedOrders, + latitude: json['latitude']?.toString(), + longitude: json['longitude']?.toString(), + distance: json['distance']?.toDouble(), + ratings: (json['ratings'] as List?)?.map((e) => RatingModel.fromJson(e)).toList() ?? [], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'email': email, + 'role': role, + 'phone_number': phoneNumber, + 'address': address, + 'shop_description': shopDescription, + 'profile_photo': profilePhoto, + 'gallery': gallery, + 'total_orders': totalOrders, + 'created_at': createdAt.toIso8601String(), + 'updated_at': updatedAt.toIso8601String(), + 'specializations': specializations, + 'average_rating': average_rating, + 'completed_orders': completed_orders, + 'latitude': latitude, + 'longitude': longitude, + 'distance': distance, + 'ratings': ratings.map((e) => e.toJson()).toList(), + }; + } + + // Mengembalikan kategori spesialisasi yang dikelompokkan + Map> get specializationsByCategory { + final Map> result = {}; + + for (var spec in specializations) { + if (!result.containsKey(spec.category)) { + result[spec.category] = []; + } + result[spec.category]!.add(spec); + } + + return result; + } + + // Mendapatkan URL lengkap untuk foto profil + String getFullProfilePhotoUrl() { + if (profilePhoto == null || profilePhoto!.isEmpty) { + return ''; + } + + return ApiService.getFullImageUrl(profilePhoto!); + } + + // Mendapatkan jarak dalam format yang lebih mudah dibaca + String getFormattedDistance() { + if (distance == null) { + return 'Tidak diketahui'; + } else if (distance! < 1) { + return '${(distance! * 1000).toStringAsFixed(0)} m'; + } else { + return '${distance!.toStringAsFixed(1)} km'; + } + } + + // Tambahkan method untuk memperbarui jarak + void updateDistance(double newDistance) { + distance = newDistance; + } + + // Method untuk mengecek apakah model memiliki data lokasi valid + bool hasValidLocation() { + return latitude != null && + longitude != null && + latitude!.isNotEmpty && + longitude!.isNotEmpty; + } +} + +class RatingInfo { + final double averageRating; + final int totalReviews; + + RatingInfo({ + required this.averageRating, + required this.totalReviews, + }); + + factory RatingInfo.fromJson(Map json) { + return RatingInfo( + averageRating: (json['average_rating'] ?? 0).toDouble(), + totalReviews: json['total_reviews'] ?? 0, + ); + } + + Map toJson() { + return { + 'average_rating': averageRating, + 'total_reviews': totalReviews, + }; + } +} diff --git a/TA_android/lib/core/models/user_model.dart b/TA_android/lib/core/models/user_model.dart new file mode 100644 index 0000000..2e67106 --- /dev/null +++ b/TA_android/lib/core/models/user_model.dart @@ -0,0 +1,185 @@ +import '../utils/url_helper.dart'; + +class User { + final int id; + final String name; + final String email; + final String role; + final String phoneNumber; + final String address; + final String? latitude; + final String? longitude; + final String? shopDescription; + final String? profilePhoto; + final String? emailVerifiedAt; + final String createdAt; + final String updatedAt; + final List? preferredSpecializations; + final List? gallery; + + User({ + required this.id, + required this.name, + required this.email, + required this.role, + required this.phoneNumber, + required this.address, + this.latitude, + this.longitude, + this.shopDescription, + this.profilePhoto, + this.emailVerifiedAt, + required this.createdAt, + required this.updatedAt, + this.preferredSpecializations, + this.gallery, + }); + + factory User.fromJson(Map json) { + List? specializations; + + // Parsing specializations jika ada + if (json['preferred_specializations'] != null) { + specializations = (json['preferred_specializations'] as List) + .map((item) => Specialization.fromJson(item)) + .toList(); + } + + // Parsing gallery jika ada + List? galleryList; + if (json['gallery'] != null) { + galleryList = + (json['gallery'] as List).map((item) => item.toString()).toList(); + } + + // Process profile photo URL - ensure it's a complete URL + String? profilePhoto = json['profile_photo']; + + // Konversi URL foto profil jika ada + // ignore_for_file: avoid_print + if (profilePhoto != null && profilePhoto.isNotEmpty) { + // Gunakan UrlHelper yang aman dari import cycle + profilePhoto = UrlHelper.getFullImageUrl(profilePhoto); + print('DEBUG: URL foto profil: $profilePhoto'); + } + + return User( + id: json['id'], + name: json['name'], + email: json['email'], + role: json['role'], + phoneNumber: json['phone_number'], + address: json['address'], + latitude: json['latitude']?.toString(), + longitude: json['longitude']?.toString(), + shopDescription: json['shop_description'], + profilePhoto: profilePhoto, + emailVerifiedAt: json['email_verified_at'], + createdAt: json['created_at'], + updatedAt: json['updated_at'], + preferredSpecializations: specializations, + gallery: galleryList, + ); + } + + bool isPenjahit() { + return role == 'penjahit'; + } + + bool isPelanggan() { + return role == 'pelanggan'; + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'email': email, + 'role': role, + 'phone_number': phoneNumber, + 'address': address, + 'latitude': latitude, + 'longitude': longitude, + 'shop_description': shopDescription, + 'profile_photo': profilePhoto, + 'email_verified_at': emailVerifiedAt, + 'created_at': createdAt, + 'updated_at': updatedAt, + 'preferred_specializations': + preferredSpecializations?.map((s) => s.toJson()).toList(), + 'gallery': gallery, + }; + } +} + +class Specialization { + final int id; + final String name; + final String category; + final String? icon; + final String? photo; + final String? createdAt; + final String? updatedAt; + final Pivot? pivot; + + Specialization({ + required this.id, + required this.name, + required this.category, + this.icon, + this.photo, + this.createdAt, + this.updatedAt, + this.pivot, + }); + + factory Specialization.fromJson(Map json) { + return Specialization( + id: json['id'], + name: json['name'], + category: json['category'], + icon: json['icon'], + photo: json['photo'], + createdAt: json['created_at'], + updatedAt: json['updated_at'], + pivot: json['pivot'] != null ? Pivot.fromJson(json['pivot']) : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'category': category, + 'icon': icon, + 'photo': photo, + 'created_at': createdAt, + 'updated_at': updatedAt, + 'pivot': pivot?.toJson(), + }; + } +} + +class Pivot { + final int userId; + final int tailorSpecializationId; + + Pivot({ + required this.userId, + required this.tailorSpecializationId, + }); + + factory Pivot.fromJson(Map json) { + return Pivot( + userId: json['user_id'], + tailorSpecializationId: json['tailor_specialization_id'], + ); + } + + Map toJson() { + return { + 'user_id': userId, + 'tailor_specialization_id': tailorSpecializationId, + }; + } +} diff --git a/TA_android/lib/core/models/wallet_model.dart b/TA_android/lib/core/models/wallet_model.dart new file mode 100644 index 0000000..aa953d0 --- /dev/null +++ b/TA_android/lib/core/models/wallet_model.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'wallet_transaction_model.dart'; + +class WalletModel { + final String balance; + final String pendingWithdrawals; + final String availableBalance; + final List transactions; + + WalletModel({ + required this.balance, + required this.pendingWithdrawals, + required this.availableBalance, + required this.transactions, + }); + + factory WalletModel.fromJson(Map json) { + return WalletModel( + balance: json['balance']?.toString() ?? '0', + pendingWithdrawals: json['pending_withdrawals']?.toString() ?? '0', + availableBalance: json['available_balance']?.toString() ?? '0', + transactions: (json['transactions'] as List?) + ?.map((transaction) => WalletTransaction.fromJson(transaction)) + .toList() ?? + [], + ); + } + + // Helper method untuk mendapatkan balance dalam format double + double getBalanceAsDouble() { + try { + return double.parse(balance); + } catch (e) { + return 0.0; + } + } + + // Helper method untuk mendapatkan pending withdrawals dalam format double + double getPendingWithdrawalsAsDouble() { + try { + return double.parse(pendingWithdrawals); + } catch (e) { + return 0.0; + } + } + + // Helper method untuk mendapatkan available balance dalam format double + double getAvailableBalanceAsDouble() { + try { + return double.parse(availableBalance); + } catch (e) { + return 0.0; + } + } +} + +class BankAccount { + final int id; + final String bankName; + final String accountNumber; + final String accountHolderName; + final String status; + final String? verifiedAt; + final String? rejectionReason; + final String createdAt; + final String updatedAt; + + BankAccount({ + required this.id, + required this.bankName, + required this.accountNumber, + required this.accountHolderName, + required this.status, + this.verifiedAt, + this.rejectionReason, + required this.createdAt, + required this.updatedAt, + }); + + factory BankAccount.fromJson(Map json) { + return BankAccount( + id: json['id'], + bankName: json['bank_name'], + accountNumber: json['account_number'], + accountHolderName: json['account_holder_name'], + status: json['status'], + verifiedAt: json['verified_at'], + rejectionReason: json['rejection_reason'], + createdAt: json['created_at'], + updatedAt: json['updated_at'], + ); + } + + // Helper method untuk mendapatkan status dalam bahasa Indonesia + String getStatusText() { + switch (status.toLowerCase()) { + case 'pending': + return 'Menunggu Verifikasi'; + case 'active': + return 'Aktif'; + case 'rejected': + return 'Ditolak'; + default: + return 'Status Tidak Diketahui'; + } + } + + // Helper method untuk mendapatkan warna status + Color getStatusColor() { + switch (status.toLowerCase()) { + case 'pending': + return const Color(0xFFFFA000); // Orange + case 'active': + return const Color(0xFF34A853); // Hijau + case 'rejected': + return const Color(0xFFEA4335); // Merah + default: + return const Color(0xFF9AA0A6); // Abu-abu + } + } +} diff --git a/TA_android/lib/core/models/wallet_transaction_model.dart b/TA_android/lib/core/models/wallet_transaction_model.dart new file mode 100644 index 0000000..0a8a91c --- /dev/null +++ b/TA_android/lib/core/models/wallet_transaction_model.dart @@ -0,0 +1,186 @@ +import 'package:flutter/material.dart'; + +class WalletTransaction { + final int id; + final int walletId; + final int? bookingId; + final String type; + final String amount; + final String description; + final String status; + final String createdAt; + final String updatedAt; + final BookingTransaction? booking; + + WalletTransaction({ + required this.id, + required this.walletId, + this.bookingId, + required this.type, + required this.amount, + required this.description, + required this.status, + required this.createdAt, + required this.updatedAt, + this.booking, + }); + + factory WalletTransaction.fromJson(Map json) { + return WalletTransaction( + id: json['id'], + walletId: json['wallet_id'], + bookingId: json['booking_id'], + type: json['type'], + amount: json['amount'], + description: json['description'], + status: json['status'], + createdAt: json['created_at'], + updatedAt: json['updated_at'], + booking: json['booking'] != null + ? BookingTransaction.fromJson(json['booking']) + : null, + ); + } + + // Helper method untuk mendapatkan amount dalam format double + double getAmountAsDouble() { + try { + return double.parse(amount); + } catch (e) { + return 0.0; + } + } + + // Helper method untuk mendapatkan tipe transaksi dalam bahasa Indonesia + String getTypeText() { + switch (type.toLowerCase()) { + case 'credit': + return 'Masuk'; + case 'debit': + return 'Keluar'; + default: + return 'Tidak Diketahui'; + } + } + + // Helper method untuk mendapatkan warna berdasarkan tipe transaksi + Color getTypeColor() { + switch (type.toLowerCase()) { + case 'credit': + return const Color(0xFF34A853); // Hijau + case 'debit': + return const Color(0xFFEA4335); // Merah + default: + return const Color(0xFF9AA0A6); // Abu-abu + } + } + + // Helper method untuk mendapatkan icon berdasarkan tipe transaksi + IconData getTypeIcon() { + switch (type.toLowerCase()) { + case 'credit': + return Icons.arrow_downward; + case 'debit': + return Icons.arrow_upward; + default: + return Icons.swap_horiz; + } + } +} + +class BookingTransaction { + final int id; + final String transactionCode; + final int customerId; + final int tailorId; + final String appointmentDate; + final String appointmentTime; + final String serviceType; + final String category; + final String? designPhoto; + final String? notes; + final String status; + final String totalPrice; + final String paymentStatus; + final Map? measurements; + final String? repairDetails; + final String? repairPhoto; + final String? repairNotes; + final String? completionPhoto; + final String? completionNotes; + final String? acceptedAt; + final String? rejectedAt; + final String? completedAt; + final String? pickupDate; + final String? rejectionReason; + final String paymentMethod; + final String? midtransSnapToken; + final String createdAt; + final String updatedAt; + + BookingTransaction({ + required this.id, + required this.transactionCode, + required this.customerId, + required this.tailorId, + required this.appointmentDate, + required this.appointmentTime, + required this.serviceType, + required this.category, + this.designPhoto, + this.notes, + required this.status, + required this.totalPrice, + required this.paymentStatus, + this.measurements, + this.repairDetails, + this.repairPhoto, + this.repairNotes, + this.completionPhoto, + this.completionNotes, + this.acceptedAt, + this.rejectedAt, + this.completedAt, + this.pickupDate, + this.rejectionReason, + required this.paymentMethod, + this.midtransSnapToken, + required this.createdAt, + required this.updatedAt, + }); + + factory BookingTransaction.fromJson(Map json) { + return BookingTransaction( + id: json['id'], + transactionCode: json['transaction_code'], + customerId: json['customer_id'], + tailorId: json['tailor_id'], + appointmentDate: json['appointment_date'], + appointmentTime: json['appointment_time'], + serviceType: json['service_type'], + category: json['category'], + designPhoto: json['design_photo'], + notes: json['notes'], + status: json['status'], + totalPrice: json['total_price'], + paymentStatus: json['payment_status'], + measurements: json['measurements'] != null + ? Map.from(json['measurements']) + : null, + repairDetails: json['repair_details'], + repairPhoto: json['repair_photo'], + repairNotes: json['repair_notes'], + completionPhoto: json['completion_photo'], + completionNotes: json['completion_notes'], + acceptedAt: json['accepted_at'], + rejectedAt: json['rejected_at'], + completedAt: json['completed_at'], + pickupDate: json['pickup_date'], + rejectionReason: json['rejection_reason'], + paymentMethod: json['payment_method'], + midtransSnapToken: json['midtrans_snap_token'], + createdAt: json['created_at'], + updatedAt: json['updated_at'], + ); + } +} diff --git a/TA_android/lib/core/models/withdrawals_model.dart b/TA_android/lib/core/models/withdrawals_model.dart new file mode 100644 index 0000000..e69de29 diff --git a/TA_android/lib/core/providers/user_provider.dart b/TA_android/lib/core/providers/user_provider.dart new file mode 100644 index 0000000..5e07328 --- /dev/null +++ b/TA_android/lib/core/providers/user_provider.dart @@ -0,0 +1,200 @@ +import 'package:flutter/foundation.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert'; +import '../models/user_model.dart'; +import '../utils/logger.dart'; +// ignore_for_file: avoid_print + +class UserProvider extends ChangeNotifier { + User? _user; + + User? get user => _user; + + bool get isLoggedIn => _user != null; + + // Mengatur user dari data json + Future setUser(Map userData) async { + try { + print( + 'DEBUG PROVIDER: Menerima data user untuk disimpan. Keys: ${userData.keys.join(', ')}'); + + // Log profile photo jika ada + if (userData.containsKey('profile_photo')) { + print( + 'DEBUG PROVIDER: profile_photo yang diterima: ${userData['profile_photo']}'); + } else { + print('DEBUG PROVIDER: Tidak ada profile_photo dalam data user'); + } + + _user = User.fromJson(userData); + + // Log data user setelah konversi + print( + 'DEBUG PROVIDER: User setelah konversi. Profile photo: ${_user?.profilePhoto}'); + + // Simpan data user ke SharedPreferences + await _saveUserToPrefs(); + + notifyListeners(); + } catch (e) { + print('Error setting user: $e'); + print('Stack trace: ${StackTrace.current}'); + } + } + + // Memperbarui user dari data json dari API profile + Future updateUserFromJson(Map userData) async { + try { + AppLogger.info('Memperbarui data pengguna dari profil API', + tag: 'UserProvider'); + AppLogger.debug('Data profil yang diterima: ${userData.keys.join(', ')}', + tag: 'UserProvider'); + + // Konversi data ke model User + final updatedUser = User.fromJson(userData); + + // Update data user yang ada dengan data terbaru + _user = updatedUser; + + // Simpan perubahan ke SharedPreferences + await _saveUserToPrefs(); + + AppLogger.info('Data pengguna berhasil diperbarui dari profil API', + tag: 'UserProvider'); + notifyListeners(); + } catch (e) { + AppLogger.error('Gagal memperbarui data pengguna dari profil API', + error: e, tag: 'UserProvider'); + } + } + + // Menyimpan data user ke SharedPreferences + Future _saveUserToPrefs() async { + if (_user == null) return; + + try { + final prefs = await SharedPreferences.getInstance(); + final userJson = jsonEncode(_user!.toJson()); + await prefs.setString('user_data', userJson); + print('Data user berhasil disimpan ke SharedPreferences'); + } catch (e) { + print('Error saving user to SharedPreferences: $e'); + } + } + + // Memuat data user dari SharedPreferences + Future loadUserFromPrefs() async { + try { + final prefs = await SharedPreferences.getInstance(); + final userJson = prefs.getString('user_data'); + + if (userJson != null) { + _user = User.fromJson(jsonDecode(userJson)); + notifyListeners(); + return true; + } + return false; + } catch (e) { + print('Error loading user from SharedPreferences: $e'); + return false; + } + } + + // Menghapus data user saat logout + Future clearUser() async { + try { + _user = null; + + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('user_data'); + + notifyListeners(); + } catch (e) { + print('Error clearing user: $e'); + } + } + + // Update data user + Future updateUser(Map updatedData) async { + if (_user == null) return; + + try { + // Gabungkan data user yang ada dengan data yang diupdate + final Map currentData = _user!.toJson(); + final Map newData = {...currentData, ...updatedData}; + + _user = User.fromJson(newData); + + // Simpan perubahan ke SharedPreferences + await _saveUserToPrefs(); + + notifyListeners(); + } catch (e) { + print('Error updating user: $e'); + } + } + + // Update foto profil user + Future updateUserPhoto(String photoUrl) async { + if (_user == null) return; + + try { + _user = User( + id: _user!.id, + name: _user!.name, + email: _user!.email, + phoneNumber: _user!.phoneNumber, + address: _user!.address, + emailVerifiedAt: _user!.emailVerifiedAt, + profilePhoto: photoUrl, // Update foto profil + latitude: _user!.latitude, + longitude: _user!.longitude, + role: _user!.role, + createdAt: _user!.createdAt, + updatedAt: _user!.updatedAt, + preferredSpecializations: _user!.preferredSpecializations, + shopDescription: _user!.shopDescription, + gallery: _user!.gallery, + ); + + // Simpan perubahan ke SharedPreferences + await _saveUserToPrefs(); + + notifyListeners(); + } catch (e) { + print('Error updating user photo: $e'); + } + } + + // Update galeri foto user + Future updateUserGallery(List galleryUrls) async { + if (_user == null) return; + + try { + _user = User( + id: _user!.id, + name: _user!.name, + email: _user!.email, + phoneNumber: _user!.phoneNumber, + address: _user!.address, + emailVerifiedAt: _user!.emailVerifiedAt, + profilePhoto: _user!.profilePhoto, + latitude: _user!.latitude, + longitude: _user!.longitude, + role: _user!.role, + createdAt: _user!.createdAt, + updatedAt: _user!.updatedAt, + preferredSpecializations: _user!.preferredSpecializations, + shopDescription: _user!.shopDescription, + gallery: galleryUrls, // Update gallery + ); + + // Simpan perubahan ke SharedPreferences + await _saveUserToPrefs(); + + notifyListeners(); + } catch (e) { + print('Error updating user gallery: $e'); + } + } +} diff --git a/TA_android/lib/core/routes/routes.dart b/TA_android/lib/core/routes/routes.dart new file mode 100644 index 0000000..02455c0 --- /dev/null +++ b/TA_android/lib/core/routes/routes.dart @@ -0,0 +1,156 @@ +import 'package:flutter/material.dart'; +import '../../pages/splash_screen.dart'; +import '../../pages/onboarding_page.dart'; +import '../../pages/register_option_page.dart'; +import '../../pages/auth/login_page.dart'; +import '../../pages/auth/register_customer_page.dart'; +import '../../pages/auth/login_tailor_page.dart'; +import '../../pages/costumer/main_page.dart' as customer; +import '../../pages/costumer/order/payment_page.dart'; +import '../../pages/tailor/main_page.dart' as tailor; +import '../../pages/debug/debug_page.dart'; +import '../../pages/costumer/home/booking_page.dart'; +// ignore_for_file: avoid_print + +class AppRoutes { + // Definisi nama route + static const String splash = '/'; + static const String onboarding = '/onboarding'; + static const String registerOption = '/register-option'; + static const String login = '/login'; + static const String registerCustomer = '/register-customer'; + static const String loginTailor = '/login-tailor'; + static const String customerHome = '/customer-home'; + static const String tailorHome = '/tailor-home'; + static const String editProfile = '/edit-profile'; + static const String payment = '/payment'; + static const String debug = '/debug'; + static const String booking = '/booking'; + + // Map untuk routes + static Map getRoutes() { + return { + splash: (context) => const SplashScreen(), + onboarding: (context) => const OnboardingPage(), + registerOption: (context) => const RegisterOptionPage(), + login: (context) => const LoginPage(), + registerCustomer: (context) => const RegisterCustomerPage(), + loginTailor: (context) => const LoginTailorPage(), + customerHome: (context) => const customer.MainPage(), + tailorHome: (context) => const tailor.MainPage(), + payment: (context) { + // Ambil parameter dari arguments route + final args = ModalRoute.of(context)!.settings.arguments as Map?; + if (args == null) { + // Jika tidak ada argumen, tampilkan halaman error + return Scaffold( + appBar: AppBar(title: const Text('Error')), + body: const Center(child: Text('Informasi pembayaran tidak lengkap')), + ); + } + + // Ekstrak parameter yang diperlukan + final bookingId = args['bookingId'] as int; + final transactionCode = args['transactionCode'] as String? ?? 'N/A'; + + // Konversi totalPrice ke integer untuk menghindari error + int totalPrice = 0; + if (args['totalPrice'] is int) { + totalPrice = args['totalPrice']; + } else if (args['totalPrice'] is String) { + try { + String numericString = (args['totalPrice'] as String).replaceAll(RegExp(r'[^0-9]'), ''); + if (numericString.isNotEmpty) { + totalPrice = int.parse(numericString); + } + } catch (e) { + print('Error parsing totalPrice in route: $e'); + } + } + + // Kembalikan halaman payment dengan parameter yang benar + return PaymentPage( + bookingId: bookingId, + transactionCode: transactionCode, + totalPrice: totalPrice, + ); + }, + debug: (context) => const DebugPage(), + booking: (context) { + final args = + ModalRoute.of(context)!.settings.arguments as Map; + return BookingPage( + tailorId: args['tailorId'], + tailorName: args['tailorName'], + tailorImage: args['tailorImage'], + ); + }, + }; + } + + static Route onGenerateRoute(RouteSettings settings) { + // Extract the route name from the settings + final String? route = settings.name; + + // Check for specific pages with custom transitions or handlers + switch (route) { + // ... other routes + + case '/payment': + // Pastikan argumen didapat dan dikonversi dengan benar + final Map? args = settings.arguments as Map?; + + if (args != null && args['bookingId'] != null && args.containsKey('totalPrice')) { + // Konversi totalPrice ke integer untuk menghindari error + int bookingId = args['bookingId'] is int ? args['bookingId'] : 0; + String transactionCode = args['transactionCode'] as String? ?? 'N/A'; + + // Konversi totalPrice ke integer + int totalPrice = 0; + if (args['totalPrice'] is int) { + totalPrice = args['totalPrice']; + } else if (args['totalPrice'] is String) { + try { + String numericString = (args['totalPrice'] as String).replaceAll(RegExp(r'[^0-9]'), ''); + if (numericString.isNotEmpty) { + totalPrice = int.parse(numericString); + } + } catch (e) { + print('Error parsing totalPrice in route: $e'); + } + } + + return MaterialPageRoute( + builder: (_) => PaymentPage( + bookingId: bookingId, + transactionCode: transactionCode, + totalPrice: totalPrice, + ), + ); + } + + // Jika tidak ada argumen yang valid, tampilkan halaman error + return MaterialPageRoute( + builder: (_) => Scaffold( + appBar: AppBar(title: const Text('Error')), + body: const Center( + child: Text('No payment information provided'), + ), + ), + ); + + // ... other routes + + default: + // Return the default route for unknown routes + return MaterialPageRoute( + builder: (_) => Scaffold( + appBar: AppBar(title: const Text('Error')), + body: const Center( + child: Text('Page not found'), + ), + ), + ); + } + } +} diff --git a/TA_android/lib/core/services/api_service.dart b/TA_android/lib/core/services/api_service.dart new file mode 100644 index 0000000..e64fcaf --- /dev/null +++ b/TA_android/lib/core/services/api_service.dart @@ -0,0 +1,3234 @@ +import 'dart:convert'; +import 'dart:math'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; +import 'shared_prefs_helper.dart'; +import 'dart:io'; +import '../models/tailor_model.dart'; +import '../models/gallery_model.dart'; +import '../utils/logger.dart'; +import '../utils/url_helper.dart'; +// ignore_for_file: avoid_print + +class ApiService { + // Gunakan env variable untuk base URL + static String get baseUrl => UrlHelper.baseUrl; + static String get imageBaseUrl => UrlHelper.imageBaseUrl; + + static bool _isInitialized = false; + + /// Initialize API Service and check if shared preferences is working + static Future init() async { + if (_isInitialized) return; + + print('Initializing ApiService...'); + + // Check if shared preferences is working + final sharedPrefsWorking = await SharedPrefsHelper.checkIfWorking(); + + if (!sharedPrefsWorking) { + print('WARNING: SharedPreferences tidak berfungsi dengan baik!'); + print('Mencoba memperbaiki SharedPreferences...'); + + final fixed = await SharedPrefsHelper.tryToFix(); + + if (fixed) { + print('SharedPreferences berhasil diperbaiki'); + } else { + print('PERINGATAN PENTING: SharedPreferences masih bermasalah!'); + print('Aplikasi akan menggunakan penyimpanan memory sebagai fallback'); + } + } else { + print('SharedPreferences berfungsi dengan baik'); + } + + _isInitialized = true; + } + + // Mendapatkan token dari shared preferences + static Future getToken() async { + try { + print('DEBUG: Mencoba mendapatkan token dari SharedPreferences...'); + + final prefs = await SharedPreferences.getInstance(); + print('DEBUG: SharedPreferences instance berhasil dibuat'); + + final token = prefs.getString('auth_token'); + print( + 'DEBUG: Hasil membaca auth_token: ${token == null ? "null" : "ditemukan"}'); + + if (token == null) { + print('getToken: Token tidak ditemukan di SharedPreferences'); + + // Coba ambil dari memory storage sebagai fallback + print('DEBUG: Mencoba mendapatkan token dari memory storage...'); + final memoryToken = SharedPrefsHelper.getTokenFromMemory(); + if (memoryToken != null) { + print('DEBUG: Token ditemukan di memory storage'); + return memoryToken; + } + } else { + if (token.length > 10) { + print('getToken: Token ditemukan: ${token.substring(0, 10)}...'); + } else { + print('getToken: Token ditemukan terlalu pendek: $token'); + } + } + + return token; + } catch (e) { + print('ERROR KRITIS saat mengambil token: $e'); + print('ERROR STACK TRACE: ${StackTrace.current}'); + + // Jika error, coba dapatkan dari memory storage + return SharedPrefsHelper.getTokenFromMemory(); + } + } + + // Menyimpan token ke shared preferences + static Future saveToken(String token) async { + if (token.isEmpty) { + print('ERROR: Mencoba menyimpan token kosong! Operasi dibatalkan'); + return; + } + + // Simpan ke memory storage sebagai backup + SharedPrefsHelper.saveTokenToMemory(token); + + try { + print('DEBUG: Mencoba menyimpan token ke SharedPreferences...'); + + print( + 'DEBUG: Token yang akan disimpan (10 karakter pertama): ${token.substring(0, min(10, token.length))}'); + + final prefs = await SharedPreferences.getInstance(); + print( + 'DEBUG: SharedPreferences instance berhasil dibuat untuk saveToken'); + + final result = await prefs.setString('auth_token', token); + print('DEBUG: Hasil dari setString: $result'); + + if (result) { + print( + 'Token berhasil disimpan: ${token.substring(0, min(10, token.length))}...'); + } else { + print( + 'WARNING: Token mungkin gagal disimpan, hasil setString: $result'); + + // Coba verifikasi penyimpanan token + final isWorking = await SharedPrefsHelper.checkIfWorking(); + if (!isWorking) { + print( + 'DEBUG: SharedPreferences tidak berfungsi dengan baik, mencoba memperbaiki...'); + await SharedPrefsHelper.tryToFix(); + + // Coba simpan token lagi setelah perbaikan + final prefs = await SharedPreferences.getInstance(); + final retryResult = await prefs.setString('auth_token', token); + print('DEBUG: Hasil menyimpan token setelah perbaikan: $retryResult'); + } + } + + // Verifikasi token setelah disimpan + final savedToken = prefs.getString('auth_token'); + if (savedToken == null) { + print( + 'ERROR: Verifikasi gagal - token tidak ditemukan setelah disimpan!'); + } else { + print('DEBUG: Verifikasi berhasil - token ditemukan setelah disimpan'); + } + } catch (e) { + print('ERROR KRITIS saat menyimpan token: $e'); + print('ERROR STACK TRACE: ${StackTrace.current}'); + print( + 'Catatan: Token tetap tersimpan di memory storage sebagai fallback'); + } + } + + // Menghapus token saat logout + static Future removeToken() async { + try { + // Hapus dari memory storage + SharedPrefsHelper.removeTokenFromMemory(); + + print('DEBUG: Mencoba menghapus token dari SharedPreferences...'); + final prefs = await SharedPreferences.getInstance(); + final result = await prefs.remove('auth_token'); + + if (result) { + print('Token autentikasi berhasil dihapus dari SharedPreferences'); + } else { + print('WARNING: Gagal menghapus token dari SharedPreferences'); + } + + // Verifikasi penghapusan + final tokenAfterRemoval = prefs.getString('auth_token'); + if (tokenAfterRemoval != null) { + print('ERROR: Token masih ada di SharedPreferences setelah dihapus!'); + } else { + print('DEBUG: Verifikasi penghapusan berhasil'); + } + } catch (e) { + print('ERROR KRITIS saat menghapus token: $e'); + print('ERROR STACK TRACE: ${StackTrace.current}'); + } + } + + // Fungsi untuk logout dari API dan menghapus token lokal + static Future> logout() async { + try { + // Remove token from shared preferences + await removeToken(); + + return {'success': true, 'message': 'Berhasil logout'}; + + // Uncomment bagian berikut jika endpoint logout API sudah tersedia + /* + // Get token from shared preferences + final token = await getToken(); + + if (token == null) { + return { + 'success': true, + 'message': 'Berhasil logout (tanpa API call, tidak ada token)' + }; + } + + // Setup headers + final headers = { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }; + + // Make API call to logout endpoint + final response = await http.post( + Uri.parse('$baseUrl/auth/logout'), + headers: headers, + ); + + // Remove token anyway, regardless of API response + await removeToken(); + + if (response.statusCode == 200) { + return { + 'success': true, + 'message': 'Berhasil logout' + }; + } else { + return { + 'success': true, // Still return success as we've removed the token locally + 'message': 'Berhasil logout (API error: ${response.statusCode})' + }; + } + */ + } catch (e) { + print('Error during logout: $e'); + // Still try to remove the token even if there's an error + await removeToken(); + + return { + 'success': + true, // Still return success as we've tried our best to logout + 'message': 'Berhasil logout (dengan error: $e)' + }; + } + } + + // Mendapatkan semua spesialisasi + static Future>> getSpecializations() async { + try { + print('Fetching specializations from $baseUrl/specializations/all'); + + final response = await http.get( + Uri.parse('$baseUrl/specializations/all'), + headers: { + 'Accept': 'application/json', + }, + ); + + print('Specializations response status: ${response.statusCode}'); + if (response.body.length > 500) { + print( + 'Specializations response body (truncated): ${response.body.substring(0, 500)}...'); + } else { + print('Specializations response body: ${response.body}'); + } + + if (response.statusCode == 200) { + final Map data = json.decode(response.body); + + // Handle the actual API response structure which uses 'status' instead of 'success' + if ((data['status'] == 'success' || data['success'] == true) && + data.containsKey('data')) { + final Map categoriesMap = data['data']; + List> allSpecializations = []; + + print('Processing categories: ${categoriesMap.keys.join(", ")}'); + + categoriesMap.forEach((category, specializations) { + if (specializations is List) { + for (var spec in specializations) { + if (spec is Map) { + // Create a mutable copy of the specialization + Map specCopy = + Map.from(spec); + + // Add category to the specialization data + specCopy['category'] = category; + + // Process photo URL + if (specCopy.containsKey('photo') && + specCopy['photo'] != null) { + String photoPath = specCopy['photo'] as String; + print( + 'Original photo path for ${specCopy['name']}: $photoPath'); + + // Create full URL for photo - Force HTTPS + String fullUrl = ''; + if (photoPath.startsWith('http://') || + photoPath.startsWith('https://')) { + // Already a complete URL + fullUrl = photoPath; + } else { + // Need to construct URL + if (photoPath.startsWith('/')) { + fullUrl = '$imageBaseUrl$photoPath'; + } else { + fullUrl = '$imageBaseUrl/$photoPath'; + } + } + + specCopy['fullPhotoUrl'] = fullUrl; + print('Generated image URL: ${specCopy['fullPhotoUrl']}'); + } else { + print('No photo found for ${specCopy['name']}'); + // Set a default fallback image URL + specCopy['fullPhotoUrl'] = null; + } + + allSpecializations.add(specCopy); + } + } + } + }); + + print( + 'Found ${allSpecializations.length} specializations from all categories'); + + if (allSpecializations.isNotEmpty) { + // Print one example to debug + if (allSpecializations.isNotEmpty) { + final example = allSpecializations.first; + print('Example specialization:'); + print(' Name: ${example['name']}'); + print(' Photo: ${example['photo']}'); + print(' FullPhotoUrl: ${example['fullPhotoUrl']}'); + print(' Category: ${example['category']}'); + } + + return allSpecializations; + } + } + } + + print('No specializations found or invalid response structure'); + // Jika tidak ada data yang valid, kembalikan data dummy untuk testing + return [ + { + 'id': 1, + 'name': 'Celana', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 2, + 'name': 'Rok', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 3, + 'name': 'Kemeja', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 4, + 'name': 'Seragam', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 5, + 'name': 'Jas Blazer', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 6, + 'name': 'Kebaya', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 7, + 'name': 'Gaun', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 8, + 'name': 'Gamis', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + ]; + } catch (e) { + print('Error getting specializations: $e'); + print('Error stack trace: ${StackTrace.current}'); + // Kembalikan data dummy jika terjadi error + return [ + { + 'id': 1, + 'name': 'Celana', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 2, + 'name': 'Rok', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 3, + 'name': 'Kemeja', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 4, + 'name': 'Seragam', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 5, + 'name': 'Jas Blazer', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 6, + 'name': 'Kebaya', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 7, + 'name': 'Gaun', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + { + 'id': 8, + 'name': 'Gamis', + 'category': 'Jenis Pakaian', + 'photo': null, + 'fullPhotoUrl': null + }, + ]; + } + } + + // Register tailor + static Future> registerTailor({ + required String name, + required String email, + required String password, + required String passwordConfirmation, + required String phoneNumber, + required String address, + double? latitude, + double? longitude, + String? shopDescription, + required List specializations, + }) async { + try { + // Pastikan parameter shopDescription tidak null + final String shopDesc = shopDescription?.trim() ?? ''; + + // Pastikan specializations tidak kosong + if (specializations.isEmpty) { + print('Tidak ada spesialisasi yang dipilih'); + return { + 'success': false, + 'message': 'Pilih minimal satu spesialisasi', + }; + } + + // Data untuk dikirim ke API + final Map requestData = { + 'name': name, + 'email': email, + 'password': password, + 'password_confirmation': passwordConfirmation, + 'phone_number': phoneNumber, + 'address': address, + 'shop_description': shopDesc, + 'specializations': specializations, + }; + + // Tambahkan koordinat lokasi jika ada + if (latitude != null) { + requestData['latitude'] = latitude; + } + + if (longitude != null) { + requestData['longitude'] = longitude; + } + + print('Registering tailor with data: ${json.encode(requestData)}'); + + final response = await http.post( + Uri.parse('$baseUrl/penjahit/register'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: json.encode(requestData), + ); + + print('Registration response status code: ${response.statusCode}'); + print('Registration response body: ${response.body}'); + + // Parse response body + Map responseData; + try { + responseData = json.decode(response.body); + } catch (e) { + print('Error decoding response: $e'); + return { + 'success': false, + 'message': 'Gagal membaca respons server', + }; + } + + if (response.statusCode == 200 || response.statusCode == 201) { + // Cek lokasi token dalam respons + String? token; + if (responseData.containsKey('token')) { + token = responseData['token']; + } else if (responseData.containsKey('data') && + responseData['data'] is Map) { + final data = responseData['data'] as Map; + if (data.containsKey('token')) { + token = data['token']; + } else if (data.containsKey('access_token')) { + token = data['access_token']; + } + } + + // Simpan token jika ditemukan + if (token != null && token.isNotEmpty) { + await saveToken(token); + print('Token saved: $token'); + } else { + print('No token found in response'); + print('Response structure: ${responseData.keys.join(', ')}'); + } + + return { + 'success': true, + 'message': responseData['message'] ?? 'Registrasi berhasil', + 'data': responseData['data'], + 'token': token, + }; + } else { + print('Registration failed with status code: ${response.statusCode}'); + + // Buat pesan error yang lebih informatif + String errorMessage = responseData['message'] ?? 'Registrasi gagal'; + if (responseData.containsKey('errors')) { + try { + final errors = responseData['errors'] as Map; + errorMessage = errors.values + .map((e) => e is List ? e.first : e.toString()) + .join('\n'); + } catch (e) { + print('Error processing error messages: $e'); + } + } + + return { + 'success': false, + 'message': errorMessage, + 'errors': responseData['errors'], + }; + } + } catch (e) { + print('Error during registration: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Login tailor + static Future> loginTailor({ + required String email, + required String password, + }) async { + try { + print('Logging in tailor with email: $email'); + final response = await http.post( + Uri.parse('$baseUrl/penjahit/login'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: json.encode({ + 'email': email, + 'password': password, + }), + ); + + print('Tailor login response status: ${response.statusCode}'); + print('Tailor login response body: ${response.body}'); + + final Map responseData = json.decode(response.body); + + // Log struktur respon untuk debugging + print('DEBUG API: Login response keys: ${responseData.keys.join(', ')}'); + + // Cek apakah ada data user dalam respon + if (responseData.containsKey('data') && responseData['data'] is Map) { + final dataMap = responseData['data'] as Map; + print('DEBUG API: Content of data: ${dataMap.keys.join(', ')}'); + + if (dataMap.containsKey('user') && dataMap['user'] is Map) { + final userData = dataMap['user'] as Map; + print('DEBUG API: User data keys: ${userData.keys.join(', ')}'); + + // Cek jika ada profile_photo dalam data user + if (userData.containsKey('profile_photo')) { + print( + 'DEBUG API: Profile photo in response: ${userData['profile_photo']}'); + } else { + print('DEBUG API: No profile_photo in user data'); + } + } + } + + String? token; + + if (response.statusCode == 200) { + // Cek berbagai kemungkinan lokasi token dalam respons + if (responseData.containsKey('token')) { + token = responseData['token']; + } else if (responseData.containsKey('data') && + responseData['data'] is Map) { + final data = responseData['data'] as Map; + if (data.containsKey('token')) { + token = data['token']; + } else if (data.containsKey('access_token')) { + token = data['access_token']; + } + + // Jika masih belum ada token, buat token sementara dari ID pengguna jika tersedia + if (token == null && + data.containsKey('user') && + data['user'] is Map) { + final user = data['user'] as Map; + if (user.containsKey('id')) { + // Buat pseudo-token berdasarkan ID dan email pengguna sebagai fallback + print( + 'Membuat pseudo-token lokal dari ID pengguna karena token tidak ditemukan dalam respons'); + token = + 'pseudo_token_${user['id']}_${DateTime.now().millisecondsSinceEpoch}'; + } + } + } + + // Simpan token jika ditemukan + if (token != null && token.isNotEmpty) { + await saveToken(token); + print('Tailor token saved: $token'); + } else { + print('WARNING: Tidak ada token dalam respons API login penjahit'); + print('Respons struktur: ${responseData.keys.join(', ')}'); + } + + return { + 'success': true, + 'message': responseData['message'] ?? 'Login berhasil', + 'user': _processUserDataWithCompleteUrls( + responseData.containsKey('data') && responseData['data'] is Map + ? (responseData['data'] as Map).containsKey('user') + ? (responseData['data'] as Map)['user'] + : responseData['data'] + : responseData['user'] ?? {}), + 'token': token, + }; + } else { + return { + 'success': false, + 'message': responseData['message'] ?? 'Login gagal', + }; + } + } catch (e) { + print('Error during tailor login: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Login customer + static Future> loginCustomer({ + required String email, + required String password, + }) async { + try { + print('Logging in customer with email: $email'); + final response = await http.post( + Uri.parse('$baseUrl/pelanggan/login'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: json.encode({ + 'email': email, + 'password': password, + }), + ); + + print('Customer login response status: ${response.statusCode}'); + print('Customer login response body: ${response.body}'); + + // Pastikan selalu parse respons JSON terlebih dahulu + final Map responseData = json.decode(response.body); + + // Simpan respons lengkap untuk debugging + final fullResponse = { + 'success': response.statusCode == 200, + 'status_code': response.statusCode, + 'message': responseData['message'] ?? 'Login gagal', + 'response_body': response.body, + 'data': responseData.containsKey('data') ? responseData['data'] : null, + }; + + print('DEBUG API: Respons login full data: $fullResponse'); + + String? token; + + if (response.statusCode == 200) { + // Cek berbagai kemungkinan lokasi token dalam respons + if (responseData.containsKey('token')) { + token = responseData['token']; + } else if (responseData.containsKey('data') && + responseData['data'] is Map) { + final data = responseData['data'] as Map; + if (data.containsKey('token')) { + token = data['token']; + } else if (data.containsKey('access_token')) { + token = data['access_token']; + } + + // Jika masih belum ada token, buat token sementara dari ID pengguna jika tersedia + if (token == null && + data.containsKey('user') && + data['user'] is Map) { + final user = data['user'] as Map; + if (user.containsKey('id')) { + // Buat pseudo-token berdasarkan ID dan email pengguna sebagai fallback + print( + 'Membuat pseudo-token lokal dari ID pengguna karena token tidak ditemukan dalam respons'); + token = + 'pseudo_token_${user['id']}_${DateTime.now().millisecondsSinceEpoch}'; + } + } + } + + // Simpan token jika ditemukan + if (token != null && token.isNotEmpty) { + await saveToken(token); + print('Customer token saved: $token'); + } else { + print('No token found in response for customer registration'); + print('Response structure: ${responseData.keys.join(', ')}'); + } + + return { + 'success': true, + 'message': responseData['message'] ?? 'Login berhasil', + 'user': _processUserDataWithCompleteUrls( + responseData.containsKey('data') && responseData['data'] is Map + ? (responseData['data'] as Map).containsKey('user') + ? (responseData['data'] as Map)['user'] + : responseData['data'] + : responseData['user'] ?? {}), + 'token': token, + }; + } else { + // Untuk respons error, pastikan menyertakan data error dengan lengkap + return fullResponse; + } + } catch (e) { + print('Error during customer login: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Register customer + static Future> registerCustomer({ + required String name, + required String email, + required String password, + required String phoneNumber, + required String address, + double? latitude, + double? longitude, + required List preferredSpecializations, + }) async { + try { + // Double-check: log nilai koordinat sebelum mengirim API call + print('Final koordinat lokasi akan dikirimkan ke server:'); + print('Latitude: $latitude'); + print('Longitude: $longitude'); + + // Validasi data dasar + if (preferredSpecializations.isEmpty) { + print('Tidak ada spesialisasi yang dipilih'); + return { + 'success': false, + 'message': 'Pilih minimal satu spesialisasi', + }; + } + + // Validasi latitude dan longitude - keduanya harus ada atau keduanya tidak ada + if ((latitude == null && longitude != null) || + (latitude != null && longitude == null)) { + print('Latitude dan longitude harus diisi keduanya'); + return { + 'success': false, + 'message': 'Latitude dan longitude harus diisi keduanya', + 'errors': { + 'location': 'Lokasi tidak lengkap, harap isi latitude dan longitude' + } + }; + } + + // Data untuk dikirim ke API + final Map requestData = { + 'name': name, + 'email': email, + 'password': password, + 'phone_number': phoneNumber, + 'address': address, + 'preferred_specializations': preferredSpecializations, + }; + + // Tambahkan koordinat lokasi jika ada + if (latitude != null) { + requestData['latitude'] = latitude; + } + + if (longitude != null) { + requestData['longitude'] = longitude; + } + + print('Registering customer with data: ${json.encode(requestData)}'); + + final response = await http.post( + Uri.parse('$baseUrl/pelanggan/register'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: json.encode(requestData), + ); + + print( + 'Customer registration response status code: ${response.statusCode}'); + print('Customer registration response body: ${response.body}'); + + // Parse response body + Map responseData; + try { + responseData = json.decode(response.body); + } catch (e) { + print('Error decoding response: $e'); + return { + 'success': false, + 'message': 'Gagal membaca respons server', + }; + } + + if (response.statusCode == 200 || response.statusCode == 201) { + // Cek lokasi token dalam respons + String? token; + if (responseData.containsKey('token')) { + token = responseData['token']; + } else if (responseData.containsKey('data') && + responseData['data'] is Map) { + final data = responseData['data'] as Map; + if (data.containsKey('token')) { + token = data['token']; + } else if (data.containsKey('access_token')) { + token = data['access_token']; + } + } + + // Simpan token jika ditemukan + if (token != null && token.isNotEmpty) { + await saveToken(token); + print('Customer token saved: $token'); + } else { + print('No token found in response for customer registration'); + print('Response structure: ${responseData.keys.join(', ')}'); + } + + return { + 'success': true, + 'message': responseData['message'] ?? 'Registrasi berhasil', + 'data': responseData['data'], + 'token': token, + }; + } else { + print( + 'Customer registration failed with status code: ${response.statusCode}'); + + // Buat pesan error yang lebih informatif + String errorMessage = responseData['message'] ?? 'Registrasi gagal'; + Map errorMap = {}; + + // Cek format errornya, ada dua kemungkinan: + // 1. errors ada di level utama: {"success":false, "message":"Error", "errors":{...}} + // 2. errors ada di dalam data: {"success":false, "message":"Error", "data":{...}} + if (responseData.containsKey('errors') && + responseData['errors'] != null) { + try { + // Format 1 + errorMap = responseData['errors'] as Map; + } catch (e) { + print('Error processing error messages from errors field: $e'); + } + } else if (responseData.containsKey('data') && + responseData['data'] != null) { + try { + // Format 2 - server menyimpan error di field 'data' + errorMap = responseData['data'] as Map; + } catch (e) { + print('Error processing error messages from data field: $e'); + } + } + + // Jika berhasil mendapat map error + if (errorMap.isNotEmpty) { + return { + 'success': false, + 'message': errorMessage, + 'errors': errorMap, + }; + } else { + // Jika tidak bisa mendapatkan detail error + return { + 'success': false, + 'message': errorMessage, + }; + } + } + } catch (e) { + print('Error during customer registration: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Metode diagnostik untuk memeriksa status token + static Future> checkTokenStatus() async { + try { + final result = { + 'sharedPrefsWorking': false, + 'tokenInSharedPrefs': false, + 'tokenInMemory': false, + 'tokenValue': null, + 'memoryTokenValue': null, + 'error': null, + }; + + // Periksa shared preferences + try { + final prefs = await SharedPreferences.getInstance(); + result['sharedPrefsWorking'] = true; + + final token = prefs.getString('auth_token'); + result['tokenInSharedPrefs'] = token != null; + + if (token != null && token.isNotEmpty) { + result['tokenValue'] = + token.length > 10 ? "${token.substring(0, 10)}..." : token; + } + } catch (e) { + result['error'] = 'Error SharedPreferences: $e'; + } + + // Periksa memory storage + final memoryToken = SharedPrefsHelper.getTokenFromMemory(); + result['tokenInMemory'] = memoryToken != null; + + if (memoryToken != null && memoryToken.isNotEmpty) { + result['memoryTokenValue'] = memoryToken.length > 10 + ? "${memoryToken.substring(0, 10)}..." + : memoryToken; + } + + print('DEBUG: Token status: $result'); + return result; + } catch (e) { + print('ERROR saat memeriksa status token: $e'); + return { + 'sharedPrefsWorking': false, + 'tokenInSharedPrefs': false, + 'tokenInMemory': false, + 'error': 'Terjadi kesalahan: $e', + }; + } + } + + /// Upload foto profil untuk user (pelanggan atau penjahit) + static Future> uploadProfilePhoto( + File photo, + ) async { + try { + print('DEBUG: Mencoba upload foto profil...'); + print('DEBUG: File path: ${photo.path}'); + print('DEBUG: File exists: ${photo.existsSync()}'); + + // Pastikan file ada + if (!photo.existsSync()) { + print('ERROR: File foto tidak ditemukan di: ${photo.path}'); + return { + 'success': false, + 'message': 'File foto tidak ditemukan', + }; + } + + // Dapatkan token untuk otorisasi + final token = await getToken(); + if (token == null) { + print('ERROR: Token tidak ditemukan, tidak dapat upload foto'); + return { + 'success': false, + 'message': 'Anda perlu login untuk mengupload foto profil', + }; + } + + print('DEBUG: Token ditemukan, panjang: ${token.length}'); + + // Buat request multipart + final uri = Uri.parse('$baseUrl/profile/photo'); + final request = http.MultipartRequest('POST', uri); + + // Tambahkan header otorisasi + request.headers.addAll({ + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + }); + + print('DEBUG: Headers yang dikirim: ${request.headers}'); + + // Tambahkan file foto + final fileName = photo.path.split('/').last; + final fileStream = http.ByteStream(photo.openRead()); + final fileLength = await photo.length(); + + print('DEBUG: Filename yang dikirim: $fileName'); + print('DEBUG: Ukuran file: $fileLength bytes'); + + final multipartFile = http.MultipartFile( + 'profile_photo', // nama field di API + fileStream, + fileLength, + filename: fileName, + ); + + request.files.add(multipartFile); + print('DEBUG: Field name yang digunakan: ${multipartFile.field}'); + print('DEBUG: Total files dalam request: ${request.files.length}'); + + // Kirim request + print('DEBUG: Mengirim request upload foto profil ke $uri'); + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + print('Upload foto profil status: ${response.statusCode}'); + print('Upload foto profil response: ${response.body}'); + + // Parse response + final Map responseData = json.decode(response.body); + + if (response.statusCode == 200) { + return { + 'success': true, + 'message': responseData['message'] ?? 'Foto profil berhasil diupload', + 'data': responseData['data'], + }; + } else { + return { + 'success': false, + 'message': responseData['message'] ?? 'Gagal mengupload foto profil', + 'errors': responseData['errors'], + }; + } + } catch (e) { + print('ERROR saat upload foto profil: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Menambahkan item galeri penjahit + static Future> addTailorGalleryItem({ + required File photo, + required String title, + required String description, + required String category, + }) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + // Create multipart request + var request = http.MultipartRequest( + 'POST', + Uri.parse('$baseUrl/penjahit/gallery'), + ); + + // Add headers + request.headers.addAll({ + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }); + + // Add text fields + request.fields['title'] = title; + request.fields['description'] = description; + request.fields['category'] = category; + + // Add file + var pic = await http.MultipartFile.fromPath('photo', photo.path); + request.files.add(pic); + + // Send request + var streamedResponse = await request.send(); + var response = await http.Response.fromStream(streamedResponse); + + print('Add Gallery Response: ${response.body}'); + + if (response.statusCode == 200 || response.statusCode == 201) { + final data = json.decode(response.body); + return { + 'success': true, + 'message': data['message'] ?? 'Berhasil menambahkan foto ke galeri', + 'data': data['data'] + }; + } else { + final data = json.decode(response.body); + return { + 'success': false, + 'message': data['message'] ?? 'Gagal menambahkan foto ke galeri', + }; + } + } catch (e) { + print('Error addTailorGalleryItem: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Menghapus item galeri penjahit + static Future> deleteTailorGalleryItem(int id) async { + try { + final token = await getToken(); + + if (token == null) { + print('ERROR: Token tidak ditemukan saat menghapus galeri'); + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final uri = Uri.parse('$baseUrl/penjahit/gallery/$id'); + print('DEBUG: Mengirim permintaan hapus galeri ke $uri'); + + final response = await http.delete( + uri, + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print( + 'Delete Gallery Response (Status: ${response.statusCode}): ${response.body}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + return { + 'success': true, + 'message': data['message'] ?? 'Berhasil menghapus foto dari galeri', + 'id': id, + }; + } else { + // Parse response sebagai JSON jika mungkin + Map data; + try { + data = json.decode(response.body); + } catch (e) { + data = { + 'message': 'Tidak dapat parse response: ${response.body}', + 'raw_response': response.body, + }; + } + + final message = data['message'] ?? 'Gagal menghapus foto dari galeri'; + + // Cek jika error adalah "Not Found" maka mungkin masalahnya di ID + if (response.statusCode == 404 || + message.toString().contains('No query results')) { + print('INFO: Item dengan ID $id tidak ditemukan di server'); + return { + 'success': false, + 'message': 'Item dengan ID $id tidak ditemukan', + 'error_type': 'not_found', + 'id': id, + }; + } + + return { + 'success': false, + 'message': message, + 'status_code': response.statusCode, + 'id': id, + }; + } + } catch (e) { + print('Error deleteTailorGalleryItem untuk ID $id: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + 'id': id, + }; + } + } + + /// Mendapatkan daftar galeri penjahit + static Future> getTailorGallery() async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/penjahit/gallery'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('Get Gallery Response: ${response.body}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + + // Pastikan URL gambar lengkap dengan base URL + if (data['data'] != null && data['data'] is List) { + for (var item in data['data']) { + if (item is Map && item.containsKey('photo')) { + // Gunakan utility method untuk mendapatkan URL lengkap + String photoPath = item['photo'] as String; + item['full_photo_url'] = getFullImageUrl(photoPath); + print('Generated full photo URL: ${item['full_photo_url']}'); + } + } + } + + return { + 'success': true, + 'message': 'Berhasil mendapatkan data galeri', + 'data': data['data'] + }; + } else { + final data = json.decode(response.body); + return { + 'success': false, + 'message': data['message'] ?? 'Gagal mendapatkan data galeri', + }; + } + } catch (e) { + print('Error getTailorGallery: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mengupdate item galeri penjahit + static Future> updateTailorGalleryItem({ + required int id, + required String title, + required String description, + required String category, + File? photo, + }) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + // Create multipart request if photo is provided, otherwise use normal PUT request + if (photo != null) { + var request = http.MultipartRequest( + 'POST', + Uri.parse('$baseUrl/penjahit/gallery/$id'), + ); + + // Add headers + request.headers.addAll({ + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }); + + // Add method override for PUT + request.fields['_method'] = 'PUT'; + + // Add text fields + request.fields['title'] = title; + request.fields['description'] = description; + request.fields['category'] = category; + + // Add file + var pic = await http.MultipartFile.fromPath('photo', photo.path); + request.files.add(pic); + + // Send request + var streamedResponse = await request.send(); + var response = await http.Response.fromStream(streamedResponse); + + print('Update Gallery Response: ${response.body}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + return { + 'success': true, + 'message': data['message'] ?? 'Berhasil mengupdate foto galeri', + 'data': data['data'] + }; + } else { + final data = json.decode(response.body); + return { + 'success': false, + 'message': data['message'] ?? 'Gagal mengupdate foto galeri', + }; + } + } else { + // Regular PUT request (without photo) + final response = await http.put( + Uri.parse('$baseUrl/penjahit/gallery/$id'), + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: jsonEncode({ + 'title': title, + 'description': description, + 'category': category, + }), + ); + + print('Update Gallery Response: ${response.body}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + return { + 'success': true, + 'message': data['message'] ?? 'Berhasil mengupdate data galeri', + 'data': data['data'] + }; + } else { + final data = json.decode(response.body); + return { + 'success': false, + 'message': data['message'] ?? 'Gagal mengupdate data galeri', + }; + } + } + } catch (e) { + print('Error updateTailorGalleryItem: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Fungsi pertama yang menggunakan _imageBaseUrl + static String getFullImageUrl(String? photoPath) { + return UrlHelper.getFullImageUrl(photoPath); + } + + /// Fungsi debugging untuk memeriksa ketersediaan URL gambar + static Future checkImageUrlAvailability(String url) async { + try { + print('DEBUG: Memeriksa ketersediaan gambar: $url'); + + // Buat HTTP request untuk memeriksa gambar + final response = await http.head(Uri.parse(url)); + + print('DEBUG: Status respons: ${response.statusCode}'); + print('DEBUG: Headers respons: ${response.headers}'); + + return response.statusCode >= 200 && response.statusCode < 300; + } catch (e) { + print('DEBUG: Error saat memeriksa URL gambar: $e'); + return false; + } + } + + /// Fungsi diagnostik untuk request HTTP + static Future> debugHttpRequest(String url, + {Map? headers}) async { + try { + print('\n======= DEBUG HTTP REQUEST ======='); + print('URL: $url'); + print('Headers: $headers'); + + final stopwatch = Stopwatch()..start(); + final response = await http.get(Uri.parse(url), headers: headers); + stopwatch.stop(); + + print('Status code: ${response.statusCode}'); + print('Response time: ${stopwatch.elapsedMilliseconds}ms'); + print('Content-Type: ${response.headers['content-type']}'); + print('Content-Length: ${response.headers['content-length']}'); + + if (response.statusCode >= 200 && response.statusCode < 300) { + print( + 'Response (truncated): ${response.body.length > 100 ? "${response.body.substring(0, 100)}..." : response.body}'); + print('SUCCESS: Request berhasil'); + } else { + print('ERROR: Request gagal dengan status ${response.statusCode}'); + print('Response body: ${response.body}'); + } + + print('======= END DEBUG HTTP REQUEST =======\n'); + + return { + 'success': response.statusCode >= 200 && response.statusCode < 300, + 'statusCode': response.statusCode, + 'headers': response.headers, + 'body': response.body, + 'responseTime': stopwatch.elapsedMilliseconds, + }; + } catch (e) { + print('ERROR: Exception during HTTP request: $e'); + print('ERROR STACK TRACE: ${StackTrace.current}'); + return { + 'success': false, + 'error': e.toString(), + 'stackTrace': StackTrace.current.toString(), + }; + } + } + + // Helper method untuk memproses data user dengan URL lengkap + static Map _processUserDataWithCompleteUrls( + Map userData) { + // Buat salinan data user agar tidak mengubah data asli + Map processedData = Map.from(userData); + + // Proses profile_photo jika ada + if (processedData.containsKey('profile_photo') && + processedData['profile_photo'] != null && + processedData['profile_photo'].toString().isNotEmpty) { + String photoUrl = processedData['profile_photo']; + + // Jika belum berupa URL lengkap, tambahkan base URL + if (!photoUrl.startsWith('http')) { + processedData['profile_photo'] = getFullImageUrl(photoUrl); + print( + 'DEBUG API: Processed profile photo URL to: ${processedData['profile_photo']}'); + + // Debug URL ketersediaan foto profil + checkImageUrlAvailability(processedData['profile_photo']) + .then((available) { + print( + 'DEBUG: Foto profil ${available ? "tersedia" : "TIDAK TERSEDIA"}: ${processedData['profile_photo']}'); + }); + } + } + + // Proses gallery jika ada + if (processedData.containsKey('gallery') && + processedData['gallery'] is List) { + List gallery = processedData['gallery'] as List; + List processedGallery = []; + + for (var item in gallery) { + String photoUrl = item.toString(); + if (!photoUrl.startsWith('http')) { + processedGallery.add(getFullImageUrl(photoUrl)); + } else { + processedGallery.add(photoUrl); + } + } + + processedData['gallery'] = processedGallery; + print('DEBUG API: Processed ${processedGallery.length} gallery items'); + } + + return processedData; + } + + /// Mengambil rekomendasi penjahit dari API + static Future> getRecommendedTailors() async { + try { + print('\n===== DEBUG RECOMMENDED TAILORS ====='); + print('Memulai getRecommendedTailors()'); + + final token = await getToken(); + + final headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': token != null ? 'Bearer $token' : '', + }; + + final response = await http.get( + Uri.parse('$baseUrl/tailors/recommended'), + headers: headers, + ); + + print('Response code: ${response.statusCode}'); + print('Response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + if (data['success'] == true && data['data'] != null) { + // Perbaikan: Akses data['data']['tailors'] karena struktur respons API adalah Map bukan List + List tailorsData = data['data']['tailors'] as List; + List tailors = tailorsData + .map((tailor) => TailorModel.fromJson(tailor)) + .toList(); + + // Debugging untuk tailors + print('\n===== RECOMMENDED TAILORS DETAILS ====='); + for (var tailor in tailors) { + print('----------------------------------------'); + print('Tailor ID: ${tailor.id}, Name: ${tailor.name}'); + print('Average Rating: ${tailor.average_rating}'); + print('Completed Orders: ${tailor.completed_orders}'); + } + print('========================================\n'); + + // Parse user preferences + final List userPreferred = + List.from(data['data']['user_preferred'] ?? []); + + return { + 'success': true, + 'tailors': tailors, + 'userPreferred': userPreferred, + 'message': + data['message'] ?? 'Berhasil mendapatkan rekomendasi penjahit', + }; + } + } + + return { + 'success': false, + 'tailors': [], + 'userPreferred': [], + 'message': 'Gagal mendapatkan rekomendasi penjahit', + }; + } catch (e, stackTrace) { + AppLogger.error('Error getRecommendedTailors', + error: e, stackTrace: stackTrace); + return { + 'success': false, + 'tailors': [], + 'userPreferred': [], + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mengambil galeri penjahit berdasarkan id + static Future> getTailorGalleryById(int tailorId) async { + try { + print('Fetching tailor gallery for id: $tailorId'); + final token = await getToken(); + + final headers = { + 'Accept': 'application/json', + 'Authorization': token != null ? 'Bearer $token' : '', + }; + + final response = await http.get( + Uri.parse('$baseUrl/tailors/$tailorId/gallery'), + headers: headers, + ); + + print('Tailor gallery response code: ${response.statusCode}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + print('Tailor gallery response: ${response.body}'); + + // Parse data gallery ke dalam list GalleryModel + final List galleryItems = []; + + if (data['data'] != null && data['data'] is List) { + for (var item in data['data']) { + galleryItems.add(GalleryModel.fromJson(item)); + } + } + + return { + 'success': true, + 'gallery': galleryItems, + 'message': data['message'] ?? 'Berhasil mendapatkan galeri penjahit', + }; + } else { + return { + 'success': false, + 'gallery': [], + 'message': 'Gagal mendapatkan galeri penjahit', + }; + } + } catch (e) { + print('Error getTailorGallery: $e'); + return { + 'success': false, + 'gallery': [], + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mengambil detail penjahit berdasarkan id + static Future> getTailorById(int tailorId) async { + try { + print('Fetching tailor detail for id: $tailorId'); + final token = await getToken(); + + final headers = { + 'Accept': 'application/json', + 'Authorization': token != null ? 'Bearer $token' : '', + }; + + final response = await http.get( + Uri.parse('$baseUrl/tailors/$tailorId'), + headers: headers, + ); + + print('Tailor detail response code: ${response.statusCode}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + print('Tailor detail response: ${response.body}'); + + // Parse data menjadi TailorModel + final TailorModel tailor = TailorModel.fromJson(data['data']); + + return { + 'success': true, + 'tailor': tailor, + 'message': data['message'] ?? 'Berhasil mendapatkan detail penjahit', + }; + } else { + return { + 'success': false, + 'tailor': null, + 'message': 'Gagal mendapatkan detail penjahit', + }; + } + } catch (e) { + print('Error getTailorById: $e'); + return { + 'success': false, + 'tailor': null, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Membuat booking baru + static Future> createBooking( + int tailorId, + String appointmentDate, + String appointmentTime, + String serviceType, + String category, + String notes, + File? designPhoto, + ) async { + try { + print('Creating booking for tailor: $tailorId'); + final token = await getToken(); + + final headers = { + 'Accept': 'application/json', + 'Authorization': token != null ? 'Bearer $token' : '', + }; + + // Membuat request multipart + var request = http.MultipartRequest( + 'POST', + Uri.parse('$baseUrl/tailors/$tailorId/book'), + ); + + // Menambahkan headers + request.headers.addAll(headers); + + // Menambahkan form fields + request.fields['appointment_date'] = appointmentDate; + request.fields['appointment_time'] = appointmentTime; + request.fields['service_type'] = serviceType; + request.fields['category'] = category; + request.fields['notes'] = notes; + + // Menambahkan file jika ada + if (designPhoto != null) { + request.files.add( + await http.MultipartFile.fromPath( + 'design_photo', + designPhoto.path, + ), + ); + } + + // Kirim request + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + print('Booking response code: ${response.statusCode}'); + print('Booking response: ${response.body}'); + + if (response.statusCode == 200 || response.statusCode == 201) { + final data = json.decode(response.body); + return { + 'success': true, + 'message': data['message'] ?? 'Booking berhasil dibuat', + 'data': data['data'], + }; + } else { + final error = json.decode(response.body); + return { + 'success': false, + 'message': error['message'] ?? 'Gagal membuat booking', + }; + } + } catch (e) { + print('Error createBooking: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mengambil daftar booking penjahit + static Future> getTailorBookings() async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/penjahit/bookings'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('DEBUG: Tailor bookings response status: ${response.statusCode}'); + print('DEBUG: Tailor bookings response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + // Log customer data dari API untuk debug + if (data['data'] != null && + data['data'] is List && + data['data'].isNotEmpty) { + final firstBooking = data['data'][0]; + if (firstBooking['customer'] != null) { + print( + 'DEBUG: Sample customer data received: ${firstBooking['customer']}'); + if (firstBooking['customer']['profile_photo'] != null) { + print( + 'DEBUG: Profile photo from API: ${firstBooking['customer']['profile_photo']}'); + } + } + } + + return { + 'success': true, + 'bookings': data['data'], + 'message': data['message'] ?? 'Data booking berhasil diambil', + }; + } + + final decodedResponse = jsonDecode(response.body); + return { + 'success': false, + 'message': decodedResponse['message'] ?? 'Gagal memuat data booking', + }; + } catch (e) { + print('ERROR: Gagal memuat data booking: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mengambil daftar booking penjahit berdasarkan status + static Future> getTailorBookingsByStatus( + String status) async { + try { + // Validasi status yang diterima + final validStatuses = ['diterima', 'diproses', 'selesai', 'dibatalkan']; + if (!validStatuses.contains(status.toLowerCase())) { + return { + 'success': false, + 'message': + 'Status tidak valid. Status yang valid adalah: ${validStatuses.join(", ")}' + }; + } + + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/penjahit/bookings/status/$status'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print( + 'DEBUG: Tailor bookings by status response status: ${response.statusCode}'); + + // Hanya print sebagian respons untuk debug yang lebih mudah dibaca + if (response.body.length > 300) { + print( + 'DEBUG: Tailor bookings by status response body (first 300 chars): ${response.body.substring(0, 300)}...'); + } else { + print( + 'DEBUG: Tailor bookings by status response body: ${response.body}'); + } + + if (response.statusCode == 200) { + final Map data = jsonDecode(response.body); + + if (data['data'] == null) { + print('ERROR: API Response tidak memiliki field "data"'); + return { + 'success': false, + 'message': 'Format respons API tidak valid: tidak ada data booking', + }; + } + + // Cetak informasi sampel untuk debugging + if (data['data'] is List && data['data'].isNotEmpty) { + print( + 'DEBUG: Contoh data booking pertama diterima: ${data['data'][0]}'); + + // Jika data['data'][0] berisi customer, cetak info customer pertama untuk debug + if (data['data'][0] is Map && + data['data'][0].containsKey('customer')) { + print( + 'DEBUG: Sample customer data received: ${data['data'][0]['customer']}'); + } + } + + return { + 'success': true, + 'bookings': data['data'], + 'message': data['message'] ?? 'Data booking berhasil diambil', + }; + } + + final decodedResponse = jsonDecode(response.body); + return { + 'success': false, + 'message': decodedResponse['message'] ?? 'Gagal memuat data booking', + }; + } catch (e) { + print('ERROR: Gagal memuat data booking berdasarkan status: $e'); + print('ERROR STACK TRACE: ${StackTrace.current}'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Menerima pesanan booking + static Future> acceptBooking(int bookingId) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final response = await http.post( + Uri.parse('$baseUrl/bookings/$bookingId/accept'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('DEBUG: Accept booking response status: ${response.statusCode}'); + print('DEBUG: Accept booking response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + return { + 'success': true, + 'booking': data['data']['booking'], + 'message': data['message'] ?? 'Pesanan berhasil diterima', + }; + } + + final decodedResponse = jsonDecode(response.body); + return { + 'success': false, + 'message': decodedResponse['message'] ?? 'Gagal menerima pesanan', + }; + } catch (e) { + print('ERROR: Gagal menerima pesanan: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Menolak pesanan booking + static Future> rejectBooking( + int bookingId, String reason) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + // Periksa status booking terlebih dahulu + final bookingDetail = await getBookingDetail(bookingId); + if (bookingDetail['success'] && bookingDetail['booking'] != null) { + final booking = bookingDetail['booking'] as Map; + final status = booking['status']?.toString().toLowerCase() ?? ''; + + // Cek apakah status booking adalah reservasi/pending + if (status != 'reservasi' && status != 'pending') { + return { + 'success': false, + 'message': + 'Booking dengan status "$status" tidak dapat ditolak. Hanya booking dengan status "reservasi" yang dapat ditolak.', + }; + } + } + + // Jika status valid, lanjutkan dengan permintaan API + final response = await http.post( + Uri.parse('$baseUrl/bookings/$bookingId/reject'), + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: jsonEncode({ + 'rejection_reason': reason, + }), + ); + + print('DEBUG: Reject booking response status: ${response.statusCode}'); + print('DEBUG: Reject booking response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + return { + 'success': true, + 'booking': data['data']?['booking'], + 'message': data['message'] ?? 'Pesanan berhasil ditolak', + }; + } + + // Handle error validasi dengan pesan yang lebih spesifik + final decodedResponse = jsonDecode(response.body); + String errorMessage = + decodedResponse['message'] ?? 'Gagal menolak pesanan'; + + // Cek jika ada data.error (format error spesifik) + if (decodedResponse['data'] != null && + decodedResponse['data'] is Map && + decodedResponse['data']['error'] != null) { + errorMessage = decodedResponse['data']['error']; + } + + return { + 'success': false, + 'message': errorMessage, + }; + } catch (e) { + print('ERROR: Gagal menolak pesanan: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mendapatkan detail booking berdasarkan ID + static Future> getBookingDetail(int bookingId) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + // Ambil semua booking dari endpoint yang tersedia + final response = await http.get( + Uri.parse('$baseUrl/penjahit/bookings'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('DEBUG: Booking list response status: ${response.statusCode}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + if (data['success'] && data['data'] != null && data['data'] is List) { + // Cari booking dengan ID yang sesuai + final List bookings = data['data']; + + // Metode aman untuk mencari booking dengan ID tertentu + Map? booking; + for (var item in bookings) { + if (item is Map && item['id'] == bookingId) { + booking = item; + break; + } + } + + if (booking != null) { + print('DEBUG: Booking dengan ID $bookingId ditemukan'); + return { + 'success': true, + 'booking': booking, + 'message': 'Detail pesanan berhasil diambil', + }; + } else { + print('DEBUG: Booking dengan ID $bookingId tidak ditemukan'); + return { + 'success': false, + 'message': 'Booking dengan ID $bookingId tidak ditemukan', + }; + } + } else { + print('DEBUG: Format response tidak sesuai: ${response.body}'); + return { + 'success': false, + 'message': 'Format data tidak sesuai', + }; + } + } + + print('DEBUG: Gagal mengambil data booking: ${response.body}'); + final decodedResponse = jsonDecode(response.body); + return { + 'success': false, + 'message': decodedResponse['message'] ?? 'Gagal memuat detail pesanan', + }; + } catch (e) { + print('ERROR: Gagal memuat detail pesanan: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mendapatkan role user yang sedang login + static Future getUserRole() async { + try { + final userData = await getProfile(); + if (userData['success'] && userData['user'] != null) { + return userData['user']['role']; + } + return null; + } catch (e) { + print('ERROR: Gagal mendapatkan role user: $e'); + return null; + } + } + + /// Mendapatkan data profil pengguna yang sedang login + static Future> getProfile() async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/profile'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('DEBUG: Profile response status: ${response.statusCode}'); + print('DEBUG: Profile response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + return { + 'success': true, + 'user': data['data'], + 'message': data['message'] ?? 'Profil berhasil diambil', + }; + } + + final decodedResponse = jsonDecode(response.body); + return { + 'success': false, + 'message': decodedResponse['message'] ?? 'Gagal memuat profil', + }; + } catch (e) { + print('ERROR: Gagal memuat profil: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Memperbarui data booking + static Future> updateBooking( + Map data) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final bookingId = data['booking_id']; + + final response = await http.put( + Uri.parse('$baseUrl/bookings/$bookingId'), + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: jsonEncode(data), + ); + + print('DEBUG: Update booking response status: ${response.statusCode}'); + print('DEBUG: Update booking response body: ${response.body}'); + + if (response.statusCode == 200) { + final responseData = jsonDecode(response.body); + return { + 'success': true, + 'message': responseData['message'] ?? 'Booking berhasil diperbarui', + 'data': responseData['data'], + }; + } + + final responseData = jsonDecode(response.body); + return { + 'success': false, + 'message': responseData['message'] ?? 'Gagal memperbarui booking', + }; + } catch (e) { + print('ERROR: Gagal memperbarui booking: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Memilih gambar dari galeri + static Future pickImage() async { + // Placeholder implementation + // Dalam implementasi sebenarnya perlu menggunakan plugin seperti image_picker + print('WARNING: pickImage belum diimplementasikan'); + return null; + } + + /// Mengunggah file ke server + static Future> uploadFile( + File file, String directory) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.', + }; + } + + // Placeholder implementation + // Dalam implementasi sebenarnya perlu menggunakan multipart request + print('WARNING: uploadFile belum diimplementasikan'); + + return { + 'success': false, + 'message': 'Fungsi upload belum diimplementasikan', + }; + } catch (e) { + print('ERROR: Gagal mengunggah file: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Memperbarui harga pesanan dan tanggal penyelesaian + static Future> updateBookingPrice( + int bookingId, int price, String completionDate) async { + try { + print('DEBUG: Memperbarui harga pesanan #$bookingId dengan harga $price dan tanggal selesai $completionDate'); + print('DEBUG: Tipe data price: ${price.runtimeType}'); + + // Verifikasi nilai tidak mengalami perubahan yang tidak diinginkan + if (price.toString().length > 10) { + print('ERROR: Nilai harga terlalu besar: $price. Kemungkinan ada masalah konversi.'); + } + + final token = await getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + // Pastikan data yang dikirim konsisten + final jsonBody = jsonEncode({ + 'total_price': price, + 'completion_date': completionDate, + }); + print('DEBUG: JSON yang dikirim ke server: $jsonBody'); + + final response = await http.patch( + Uri.parse('$baseUrl/bookings/$bookingId/price'), + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: jsonBody, + ); + + print('DEBUG: Update price response status: ${response.statusCode}'); + print('DEBUG: Update price response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + // Log data respons secara lebih detail + if (data['data'] != null && data['data']['booking'] != null) { + final bookingData = data['data']['booking']; + print('DEBUG: Booking data dari server: $bookingData'); + + if (bookingData['total_price'] != null) { + print('DEBUG: Harga yang diterima dari server: ${bookingData['total_price']}'); + print('DEBUG: Tipe data harga dari server: ${bookingData['total_price'].runtimeType}'); + + // Jika server mengembalikan tipe data yang berbeda, coba konversi + if (bookingData['total_price'] is String) { + final String priceStr = bookingData['total_price']; + print('DEBUG: Harga string dari server: $priceStr'); + + // Coba parse ke numerik jika memungkinkan + if (priceStr.contains('.')) { + try { + final double priceDouble = double.parse(priceStr); + print('DEBUG: Harga dikonversi ke double: $priceDouble'); + + // Update nilai dalam data respons + bookingData['total_price'] = priceDouble.toStringAsFixed(0); + print('DEBUG: Harga diupdate ke format tanpa desimal: ${bookingData['total_price']}'); + } catch (e) { + print('ERROR: Gagal mengkonversi harga: $e'); + } + } + } + } + + // Log tanggal penyelesaian yang diterima + if (bookingData['completion_date'] != null) { + print('DEBUG: Tanggal penyelesaian dari server: ${bookingData['completion_date']}'); + } + } + + return { + 'success': true, + 'message': data['message'] ?? 'Harga dan tanggal selesai berhasil diperbarui', + 'booking': data['data']?['booking'], + }; + } + + final decodedResponse = jsonDecode(response.body); + return { + 'success': false, + 'message': + decodedResponse['message'] ?? 'Gagal memperbarui harga dan tanggal selesai pesanan', + }; + } catch (e) { + print('ERROR: Gagal memperbarui harga dan tanggal selesai pesanan: $e'); + print('ERROR STACK TRACE: ${StackTrace.current}'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mendapatkan data kalender penjahit berdasarkan bulan dan tahun + static Future> getTailorCalendar( + String month, String year) async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/penjahit/calendar/$month/$year'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('DEBUG: Tailor calendar response status: ${response.statusCode}'); + print('DEBUG: Tailor calendar response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + if (data['success'] == true) { + return { + 'success': true, + 'message': data['message'] ?? 'Data kalender berhasil dimuat', + 'data': data['data'], + }; + } + + return { + 'success': false, + 'message': data['message'] ?? 'Gagal memuat data kalender', + }; + } + + // Handle error response + Map errorResponse = {}; + try { + errorResponse = jsonDecode(response.body); + } catch (e) { + errorResponse = {'message': 'Gagal memuat data kalender'}; + } + + return { + 'success': false, + 'message': errorResponse['message'] ?? 'Gagal memuat data kalender', + }; + } catch (e) { + print('ERROR: Gagal memuat data kalender: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + /// Mendapatkan data dashboard penjahit + static Future> getTailorDashboard() async { + try { + final token = await getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/penjahit/dashboard'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('DEBUG: Tailor dashboard response status: ${response.statusCode}'); + print('DEBUG: Tailor dashboard response body: ${response.body}'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + if (data['success'] == true) { + return { + 'success': true, + 'message': data['message'] ?? 'Data dashboard berhasil dimuat', + 'data': data['data'], + }; + } + + return { + 'success': false, + 'message': data['message'] ?? 'Gagal memuat data dashboard', + }; + } + + // Handle error response + Map errorResponse = {}; + try { + errorResponse = jsonDecode(response.body); + } catch (e) { + errorResponse = {'message': 'Gagal memuat data dashboard'}; + } + + return { + 'success': false, + 'message': errorResponse['message'] ?? 'Gagal memuat data dashboard', + }; + } catch (e) { + print('ERROR: Gagal memuat data dashboard: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Method untuk menyelesaikan pembayaran akhir booking + static Future> completePayment( + int bookingId, String pickupDate) async { + try { + final token = await getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + print( + 'DEBUG: Memproses pembayaran untuk booking ID: $bookingId dengan tanggal pengambilan: $pickupDate'); + + final response = await http.post( + Uri.parse('$baseUrl/bookings/$bookingId/completion-payment'), + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: jsonEncode({ + 'pickup_date': pickupDate, + }), + ); + + print('DEBUG: Respon status: ${response.statusCode}'); + print('DEBUG: Respon body: ${response.body}'); + + final Map responseData = json.decode(response.body); + + if (response.statusCode == 200) { + return { + 'success': true, + 'message': + responseData['message'] ?? 'Pembayaran berhasil dikonfirmasi', + 'booking': responseData['data'], + }; + } else { + return { + 'success': false, + 'message': responseData['message'] ?? 'Gagal memproses pembayaran', + }; + } + } catch (e) { + print('ERROR: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Tambahkan method baru untuk menghitung penjahit terdekat berdasarkan data rekomendasi + static Future> getNearbyTailors({ + required double latitude, + required double longitude, + }) async { + try { + // Gunakan data dari API rekomendasi + final result = await getRecommendedTailors(); + + print('\n===== DEBUG NEARBY TAILORS ====='); + print('Menggunakan data rekomendasi untuk menghitung penjahit terdekat'); + + if (result['success'] == true && result['tailors'] != null) { + List allTailors = result['tailors'] as List; + + // Filter penjahit yang memiliki data lokasi + List tailorsWithLocation = allTailors.where((tailor) { + return tailor.latitude != null && + tailor.longitude != null && + tailor.latitude!.isNotEmpty && + tailor.longitude!.isNotEmpty; + }).toList(); + + print('Ditemukan ${tailorsWithLocation.length} penjahit dengan data lokasi dari ${allTailors.length} total penjahit'); + + // Hitung jarak untuk setiap penjahit + for (var tailor in tailorsWithLocation) { + double tailorLat = double.tryParse(tailor.latitude!) ?? 0; + double tailorLng = double.tryParse(tailor.longitude!) ?? 0; + + // Hitung jarak menggunakan formula Haversine + double distance = + _calculateDistance(latitude, longitude, tailorLat, tailorLng); + + // Update jarak pada model + tailor.updateDistance(distance); + } + + // Urutkan berdasarkan jarak terdekat + tailorsWithLocation.sort((a, b) => (a.distance ?? double.infinity) + .compareTo(b.distance ?? double.infinity)); + + // Batasi hanya menampilkan penjahit dalam radius 10km + final nearbyTailors = tailorsWithLocation + .where( + (tailor) => tailor.distance != null && tailor.distance! <= 10) + .toList(); + + // Debug info untuk penjahit terdekat + print('\n===== NEARBY TAILORS AFTER FILTERING ====='); + for (var tailor in nearbyTailors) { + print('Tailor ID: ${tailor.id}, Name: ${tailor.name}, Distance: ${tailor.distance?.toStringAsFixed(2)} km'); + print(' - Average Rating: ${tailor.average_rating}'); + print(' - Completed Orders: ${tailor.completed_orders}'); + } + print('===========================================\n'); + + return { + 'success': true, + 'tailors': nearbyTailors, + 'message': 'Berhasil mendapatkan data penjahit terdekat', + }; + } else { + return { + 'success': false, + 'tailors': [], + 'message': + result['message'] ?? 'Gagal mendapatkan data penjahit terdekat', + }; + } + } catch (e) { + print('ERROR: Error getting nearby tailors: $e'); + return { + 'success': false, + 'tailors': [], + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Tambahkan method untuk menghitung jarak antara dua koordinat + static double _calculateDistance( + double lat1, double lon1, double lat2, double lon2) { + const double earthRadius = 6371; // Radius bumi dalam kilometer + + // Konversi derajat ke radian + double dLat = _degreesToRadians(lat2 - lat1); + double dLon = _degreesToRadians(lon2 - lon1); + + // Formula Haversine + double a = sin(dLat / 2) * sin(dLat / 2) + + cos(_degreesToRadians(lat1)) * + cos(_degreesToRadians(lat2)) * + sin(dLon / 2) * + sin(dLon / 2); + double c = 2 * atan2(sqrt(a), sqrt(1 - a)); + double distance = earthRadius * c; + + return distance; + } + + static double _degreesToRadians(double degrees) { + return degrees * pi / 180; + } + + + /// Fungsi khusus untuk memvalidasi dan men-debug URL gambar desain + static Future> validateDesignPhotoUrl(String url) async { + try { + print('\n======= DEBUG DESIGN PHOTO URL ======='); + print('URL yang akan dicek: $url'); + + // Periksa jika URL-nya valid + Uri? uri; + try { + uri = Uri.parse(url); + print('URL parsing berhasil: $uri'); + print('Scheme: ${uri.scheme}'); + print('Host: ${uri.host}'); + print('Path: ${uri.path}'); + } catch (e) { + print('URL tidak valid: $e'); + return {'success': false, 'message': 'URL tidak valid: $e', 'url': url}; + } + + // Coba lakukan request HEAD untuk memeriksa ketersediaan + try { + final headResponse = await http.head(uri); + print('HEAD response status: ${headResponse.statusCode}'); + print('HEAD response headers: ${headResponse.headers}'); + + if (headResponse.statusCode == 200) { + print('✅ URL dapat diakses dengan HEAD request'); + } else { + print( + '❌ URL tidak dapat diakses dengan HEAD request: ${headResponse.statusCode}'); + } + } catch (e) { + print('❌ Error saat melakukan HEAD request: $e'); + } + + // Coba lakukan request GET untuk memeriksa konten + try { + final stopwatch = Stopwatch()..start(); + final response = await http.get(uri); + stopwatch.stop(); + + print('GET response time: ${stopwatch.elapsedMilliseconds}ms'); + print('GET response status: ${response.statusCode}'); + print('GET response content-type: ${response.headers['content-type']}'); + print( + 'GET response content-length: ${response.headers['content-length']}'); + + if (response.statusCode == 200) { + final contentType = response.headers['content-type']; + if (contentType != null && contentType.startsWith('image/')) { + print('✅ URL berisi gambar dengan tipe: $contentType'); + + // Verifikasi jenis konten + print('Verifikasi konten sebagai gambar...'); + print('Ukuran respons: ${response.bodyBytes.length} bytes'); + + return { + 'success': true, + 'message': 'URL berisi gambar valid', + 'url': url, + 'contentType': contentType, + 'sizeBytes': response.bodyBytes.length, + 'responseTime': stopwatch.elapsedMilliseconds + }; + } else { + print('❌ URL tidak berisi gambar. Content-Type: $contentType'); + if (response.bodyBytes.length < 5000) { + print('Respons (mungkin error): ${response.body}'); + } + + return { + 'success': false, + 'message': 'URL tidak berisi gambar', + 'url': url, + 'contentType': contentType, + 'responseBody': response.bodyBytes.length < 1000 + ? response.body + : '(too large)', + 'statusCode': response.statusCode + }; + } + } else { + print('❌ GET request gagal: ${response.statusCode}'); + print('Respons error: ${response.body}'); + + return { + 'success': false, + 'message': 'GET request gagal', + 'url': url, + 'statusCode': response.statusCode, + 'responseBody': + response.bodyBytes.length < 1000 ? response.body : '(too large)' + }; + } + } catch (e) { + print('❌ Error saat melakukan GET request: $e'); + return { + 'success': false, + 'message': 'Error saat melakukan GET request', + 'url': url, + 'error': e.toString() + }; + } + + print('======= END DEBUG DESIGN PHOTO URL =======\n'); + } catch (e) { + print('ERROR: Exception during validateDesignPhotoUrl: $e'); + print('Stacktrace: ${StackTrace.current}'); + return {'success': false, 'message': 'Terjadi kesalahan: $e', 'url': url}; + } + } + + /// Fungsi untuk mendebug semua masalah URL gambar + static Future debugAllImageUrls(List urls) async { + print('\n======= DEBUG ALL IMAGE URLS ======='); + print('Jumlah URL yang akan dicek: ${urls.length}'); + + int successCount = 0; + int failCount = 0; + + for (int i = 0; i < urls.length; i++) { + final url = urls[i]; + print('\n[$i/${urls.length}] Memeriksa URL: $url'); + + try { + final result = await validateDesignPhotoUrl(url); + if (result['success'] == true) { + successCount++; + print('✅ URL #$i VALID: $url'); + } else { + failCount++; + print('❌ URL #$i TIDAK VALID: $url'); + print(' Alasan: ${result['message']}'); + } + } catch (e) { + failCount++; + print('❌ URL #$i ERROR: $e'); + } + } + + print('\nHasil pemeriksaan:'); + print('- URL valid: $successCount'); + print('- URL tidak valid/error: $failCount'); + print('======= END DEBUG ALL IMAGE URLS =======\n'); + } + + /// Fungsi untuk mendiagnosis dan memperbaiki URL gambar + static Future fixAndValidateImageUrl(String originalUrl) async { + print('\n======= DIAGNOSA DAN PERBAIKAN URL GAMBAR ======='); + print('URL original: $originalUrl'); + + // Periksa apakah URL sudah valid + var checkResult = await validateDesignPhotoUrl(originalUrl); + if (checkResult['success'] == true) { + print('✅ URL original sudah valid'); + print('======= AKHIR DIAGNOSA URL GAMBAR =======\n'); + return originalUrl; + } + + // Coba berbagai variasi URL untuk memperbaiki + List alternativeUrls = []; + + // 1. Ubah http ke https atau sebaliknya + if (originalUrl.startsWith('http://')) { + alternativeUrls.add(originalUrl.replaceFirst('http://', 'https://')); + } else if (originalUrl.startsWith('https://')) { + alternativeUrls.add(originalUrl.replaceFirst('https://', 'http://')); + } + + // 2. Cek variasi path + Uri? uri; + try { + uri = Uri.parse(originalUrl); + + // Ekstrak komponen path + final pathSegments = uri.pathSegments; + if (pathSegments.isNotEmpty) { + final lastSegment = pathSegments.last; + + // Coba dengan path langsung ke storage + if (!pathSegments.contains('storage') && + !originalUrl.contains('/storage/')) { + final newPathWithStorage = '/storage/${pathSegments.join('/')}'; + alternativeUrls + .add('${uri.scheme}://${uri.authority}$newPathWithStorage'); + } + + // Coba path dengan design_photos jika belum ada + if (!pathSegments.contains('design_photos')) { + alternativeUrls.add( + '${uri.scheme}://${uri.authority}/storage/design_photos/$lastSegment'); + } + } + } catch (e) { + print('❌ Error parsing URL untuk membuat alternatif: $e'); + } + + // 3. Tambahkan baseUrl jika URL relatif + if (!originalUrl.startsWith('http')) { + if (originalUrl.startsWith('/')) { + alternativeUrls.add('$imageBaseUrl$originalUrl'); + } else { + alternativeUrls.add('$imageBaseUrl/$originalUrl'); + } + + // Dengan /storage/ prefix + if (!originalUrl.contains('storage')) { + if (originalUrl.startsWith('/')) { + alternativeUrls.add('$imageBaseUrl/storage$originalUrl'); + } else { + alternativeUrls.add('$imageBaseUrl/storage/$originalUrl'); + } + } + } + + // Cetak semua URL alternatif + print('URL alternatif yang akan dicoba:'); + for (int i = 0; i < alternativeUrls.length; i++) { + print('[$i] ${alternativeUrls[i]}'); + } + + // Periksa semua URL alternatif + for (int i = 0; i < alternativeUrls.length; i++) { + final alternativeUrl = alternativeUrls[i]; + print('\nMencoba URL alternatif [$i]: $alternativeUrl'); + + final result = await validateDesignPhotoUrl(alternativeUrl); + if (result['success'] == true) { + print('✅ URL alternatif [$i] VALID: $alternativeUrl'); + print('======= AKHIR DIAGNOSA URL GAMBAR =======\n'); + return alternativeUrl; + } else { + print('❌ URL alternatif [$i] TIDAK VALID'); + } + } + + print('❌ Semua upaya perbaikan URL gagal'); + print('======= AKHIR DIAGNOSA URL GAMBAR =======\n'); + + // Jika semua upaya gagal, kembalikan URL original + return originalUrl; + } + + /// Fungsi khusus untuk memperbaiki URL gambar design_photos + static Future fixDesignPhotoUrl(String originalUrl) async { + try { + print('\n======= DEBUG & FIX DESIGN PHOTO URL ======='); + print('URL original: $originalUrl'); + + // Periksa jika URL sudah memakai scheme http/https + if (originalUrl.startsWith('http')) { + // Jika URL sudah lengkap, periksa apakah bisa diakses + var result = await validateDesignPhotoUrl(originalUrl); + if (result['success'] == true) { + print('✅ URL sudah valid dan bisa diakses'); + return originalUrl; + } + + // Jika tidak bisa diakses, coba ganti dari http ke https dan sebaliknya + String alternativeUrl; + if (originalUrl.startsWith('https://')) { + alternativeUrl = originalUrl.replaceFirst('https://', 'http://'); + print('Mencoba alternatif HTTP: $alternativeUrl'); + } else { + alternativeUrl = originalUrl.replaceFirst('http://', 'https://'); + print('Mencoba alternatif HTTPS: $alternativeUrl'); + } + + // Periksa URL alternatif + result = await validateDesignPhotoUrl(alternativeUrl); + if (result['success'] == true) { + print('✅ URL alternatif valid: $alternativeUrl'); + return alternativeUrl; + } + } else { + // URL tidak lengkap, coba bangun URL lengkap + List possibleUrls = []; + + // Variasi 1: Langsung tambahkan ke base URL + if (originalUrl.startsWith('/')) { + possibleUrls.add('$imageBaseUrl$originalUrl'); + } else { + possibleUrls.add('$imageBaseUrl/$originalUrl'); + } + + // Variasi 2: Tambahkan storage path jika belum ada + if (!originalUrl.contains('storage/') && + !originalUrl.contains('/storage/')) { + if (originalUrl.startsWith('/')) { + possibleUrls.add('$imageBaseUrl/storage$originalUrl'); + } else { + possibleUrls.add('$imageBaseUrl/storage/$originalUrl'); + } + } + + // Variasi 3: Jika ini adalah nama file design_photo, tambahkan path lengkap + final fileName = originalUrl.split('/').last; + // Jika namanya mengandung ekstensi gambar + if (fileName.contains('.png') || + fileName.contains('.jpg') || + fileName.contains('.jpeg')) { + possibleUrls.add('$imageBaseUrl/storage/design_photos/$fileName'); + } + + // Coba semua URL yang mungkin + print('Mencoba ${possibleUrls.length} variasi URL:'); + for (int i = 0; i < possibleUrls.length; i++) { + final url = possibleUrls[i]; + print('[$i] Mencoba: $url'); + + var result = await validateDesignPhotoUrl(url); + if (result['success'] == true) { + print('✅ URL berhasil diperbaiki: $url'); + print('======= END DEBUG & FIX DESIGN PHOTO URL =======\n'); + return url; + } + } + } + + // Upaya perbaikan gagal, kembalikan URL original + print('❌ Semua upaya perbaikan gagal. Mengembalikan URL original.'); + print('======= END DEBUG & FIX DESIGN PHOTO URL =======\n'); + + // Untuk kasus URL yang tidak valid, buat URL gambar placeholder + if (!originalUrl.startsWith('http') && !originalUrl.contains('/')) { + return 'assets/images/tailor_default.png'; + } + + return originalUrl; + } catch (e) { + print('ERROR saat memperbaiki URL gambar design: $e'); + return originalUrl; + } + } + + /// Fungsi untuk membuka dan men-debug masalah dengan gambar design + static Future debugDesignPhotoIssue(String designPhotoUrl) async { + print('\n========== DEBUGGING DESIGN PHOTO ISSUE =========='); + print('URL original: $designPhotoUrl'); + + // Info dasar server + print('\nINFO SERVER:'); + print('Base URL API: $baseUrl'); + print('Base URL Gambar: $imageBaseUrl'); + + // Check URL structure + print('\nANALISIS URL:'); + try { + Uri? uri = Uri.parse(designPhotoUrl); + print('- Scheme: ${uri.scheme}'); + print('- Host: ${uri.host}'); + print('- Path: ${uri.path}'); + print('- Query params: ${uri.queryParameters}'); + + // Check if domain is correct + if (uri.host != Uri.parse(imageBaseUrl).host) { + print('⚠️ PERINGATAN: Host URL tidak sesuai dengan imageBaseUrl!'); + } + + // Check if path contains required parts + if (!uri.path.contains('storage') && + !uri.path.contains('design_photos')) { + print( + '⚠️ PERINGATAN: Path URL tidak mengandung "storage" atau "design_photos"'); + } + + // Check file extension + final extension = uri.path.split('.').last.toLowerCase(); + if (!['jpg', 'jpeg', 'png', 'gif', 'webp'].contains(extension)) { + print( + '⚠️ PERINGATAN: Ekstensi file tidak standar untuk gambar: $extension'); + } + } catch (e) { + print('❌ URL tidak valid: $e'); + } + + // Try different variations of URL + print('\nMENCOBA VARIASI URL:'); + List variations = []; + + // Add variations based on different URL patterns + if (designPhotoUrl.startsWith('http')) { + try { + Uri uri = Uri.parse(designPhotoUrl); + String fileName = + uri.pathSegments.isNotEmpty ? uri.pathSegments.last : ''; + + if (designPhotoUrl.startsWith('https://')) { + variations.add(designPhotoUrl.replaceFirst('https://', 'http://')); + } else { + variations.add(designPhotoUrl.replaceFirst('http://', 'https://')); + } + + // Try adding or removing storage path + if (!uri.path.contains('storage')) { + var pathSegments = uri.pathSegments.toList(); + pathSegments.insert(0, 'storage'); + var newPath = '/${pathSegments.join('/')}'; + variations.add('${uri.scheme}://${uri.authority}$newPath'); + } + + // Try with direct design_photos path if it's just a file + if (fileName.isNotEmpty && fileName.contains('.')) { + variations.add('$imageBaseUrl/storage/design_photos/$fileName'); + } + } catch (e) { + print('❌ Error saat membuat variasi URL: $e'); + } + } else { + // It's a relative path or just a filename + variations.add('$imageBaseUrl/$designPhotoUrl'); + variations.add('$imageBaseUrl/storage/$designPhotoUrl'); + + // If it looks like a filename + if (!designPhotoUrl.contains('/')) { + variations.add('$imageBaseUrl/storage/design_photos/$designPhotoUrl'); + } + } + + // Test all URL variations + print('Testing ${variations.length} URL variations:'); + for (int i = 0; i < variations.length; i++) { + final variation = variations[i]; + print('\n[$i] Testing: $variation'); + + try { + final result = await validateDesignPhotoUrl(variation); + if (result['success'] == true) { + print('✅ URL variation works! $variation'); + print('Content-Type: ${result['contentType']}'); + print('Size: ${result['sizeBytes']} bytes'); + } else { + print('❌ URL variation failed: ${result['message']}'); + } + } catch (e) { + print('❌ Error testing URL variation: $e'); + } + } + + // Check server connectivity + print('\nCEK KONEKTIVITAS SERVER:'); + try { + final response = await http.get(Uri.parse('$imageBaseUrl/ping')); + print('Server base URL ping response: ${response.statusCode}'); + } catch (e) { + print('❌ Error connecting to server: $e'); + } + + print('\n========== END DEBUGGING DESIGN PHOTO ISSUE =========='); + } + + // Method untuk melakukan HTTP GET request + static Future get(String endpoint) async { + try { + AppLogger.info('GET request ke $baseUrl$endpoint', tag: 'API'); + + final token = await getToken(); + if (token == null) { + AppLogger.error('Token tidak ditemukan', tag: 'API'); + return ApiResponse( + isSuccess: false, + message: 'Token tidak ditemukan. Silakan login kembali.', + ); + } + + final response = await http.get( + Uri.parse('$baseUrl$endpoint'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + AppLogger.debug('GET response: ${response.statusCode}', tag: 'API'); + + // Parse response body + final decodedResponse = jsonDecode(response.body); + + if (response.statusCode == 200) { + return ApiResponse( + isSuccess: true, + message: decodedResponse['message'] ?? 'Berhasil mendapatkan data', + data: decodedResponse['data'], + ); + } else { + return ApiResponse( + isSuccess: false, + message: + decodedResponse['message'] ?? 'Terjadi kesalahan pada server', + ); + } + } catch (e) { + AppLogger.error('Exception pada GET request', error: e, tag: 'API'); + return ApiResponse( + isSuccess: false, + message: 'Terjadi kesalahan: $e', + ); + } + } + + static Future> getUserProfile() async { + try { + final token = await getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.', + 'data': {'name': '', 'email': ''} + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/profile'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + return { + 'success': true, + 'message': 'Berhasil mendapatkan data profil', + 'data': data['data'] ?? {'name': '', 'email': ''} + }; + } else { + return { + 'success': false, + 'message': 'Gagal mendapatkan data profil', + 'data': {'name': '', 'email': ''} + }; + } + } catch (e) { + print('Error getting user profile: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + 'data': {'name': '', 'email': ''} + }; + } + } +} + +/// Kelas untuk response API yang terstruktur +class ApiResponse { + final bool isSuccess; + final String? message; + final dynamic data; + + ApiResponse({ + required this.isSuccess, + this.message, + this.data, + }); +} diff --git a/TA_android/lib/core/services/auth_service.dart b/TA_android/lib/core/services/auth_service.dart new file mode 100644 index 0000000..3a34a9b --- /dev/null +++ b/TA_android/lib/core/services/auth_service.dart @@ -0,0 +1,50 @@ +import 'package:shared_preferences/shared_preferences.dart'; +import '../routes/routes.dart'; + +class AuthService { + static const String _tokenKey = 'auth_token'; + static const String _roleKey = 'user_role'; + static const String _userIdKey = 'user_id'; + + static Future saveAuthData( + String token, String role, int userId) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(_tokenKey, token); + await prefs.setString(_roleKey, role); + await prefs.setInt(_userIdKey, userId); + } + + static Future?> getAuthData() async { + final prefs = await SharedPreferences.getInstance(); + final token = prefs.getString(_tokenKey); + final role = prefs.getString(_roleKey); + final userId = prefs.getInt(_userIdKey); + + if (token != null && role != null && userId != null) { + return { + 'token': token, + 'role': role, + 'userId': userId, + }; + } + return null; + } + + //Digunakan untuk Logout + static Future clearAuthData() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_tokenKey); + await prefs.remove(_roleKey); + await prefs.remove(_userIdKey); + } + + static Future getInitialRoute() async { + final authData = await getAuthData(); + if (authData != null) { + return authData['role'] == 'pelanggan' + ? AppRoutes.customerHome + : AppRoutes.tailorHome; + } + return AppRoutes.login; + } +} diff --git a/TA_android/lib/core/services/booking_service.dart b/TA_android/lib/core/services/booking_service.dart new file mode 100644 index 0000000..fd45dd7 --- /dev/null +++ b/TA_android/lib/core/services/booking_service.dart @@ -0,0 +1,302 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; +import 'package:http/http.dart' as http; +import 'api_service.dart'; +// ignore_for_file: avoid_print + +class BookingService { + // Mendapatkan daftar booking pelanggan + static Future> getCustomerBookings() async { + try { + final token = await ApiService.getToken(); + + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + // Gunakan endpoint API untuk mendapatkan booking pelanggan + final response = await http.get( + Uri.parse('${ApiService.baseUrl}/bookings/customer'), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + print('DEBUG: Customer bookings response status: ${response.statusCode}'); + print('DEBUG: Customer bookings response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + if (response.statusCode == 200) { + final data = jsonDecode(response.body); + + // Tampilkan debug untuk data booking + if (data['data'] != null && data['data'] is List && data['data'].isNotEmpty) { + print('DEBUG: First booking sample data:'); + print('DEBUG: ID: ${data['data'][0]['id']}'); + print('DEBUG: Status: ${data['data'][0]['status']}'); + print('DEBUG: Transaction Code: ${data['data'][0]['transaction_code']}'); + print('DEBUG: Payment Method: ${data['data'][0]['payment_method']}'); + } + + return { + 'success': true, + 'data': data['data'], + 'message': data['message'] ?? 'Data booking berhasil diambil', + }; + } + + final decodedResponse = jsonDecode(response.body); + return { + 'success': false, + 'message': decodedResponse['message'] ?? 'Gagal memuat data booking', + }; + } catch (e) { + print('ERROR: Gagal memuat data booking pelanggan: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + static Future> createBooking({ + required int tailorId, + required String appointmentDate, + required String appointmentTime, + required String serviceType, + required String category, + String notes = '', + String paymentMethod = 'transfer_bank', + File? image, + }) async { + try { + print('DEBUG: Membuat booking baru melalui BookingService'); + print('DEBUG: Tailor ID: $tailorId'); + print('DEBUG: Tanggal: $appointmentDate'); + print('DEBUG: Waktu: $appointmentTime'); + print('DEBUG: Layanan: $serviceType'); + print('DEBUG: Kategori: $category'); + print('DEBUG: Catatan: $notes'); + print('DEBUG: Metode Pembayaran: $paymentMethod'); + print('DEBUG: Gambar: ${image != null ? 'Ada' : 'Tidak ada'}'); + + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan', + }; + } + + // Gunakan MultipartRequest untuk upload file + final request = http.MultipartRequest( + 'POST', + Uri.parse('${ApiService.baseUrl}/bookings'), + ); + + // Tambahkan headers + request.headers.addAll({ + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + }); + + // Tambahkan fields + request.fields['tailor_id'] = tailorId.toString(); + request.fields['appointment_date'] = appointmentDate; + request.fields['appointment_time'] = appointmentTime; + request.fields['service_type'] = serviceType; + request.fields['category'] = category; + request.fields['notes'] = notes; + request.fields['payment_method'] = paymentMethod; + + // Tambahkan file foto jika ada + if (image != null) { + request.files.add( + await http.MultipartFile.fromPath( + 'design_photo', + image.path, + ), + ); + } + + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + print('DEBUG: Response status code: ${response.statusCode}'); + print('DEBUG: Response body: ${response.body}'); + + final data = json.decode(response.body); + + // Menangani respons sukses + if (response.statusCode == 200 && data['success'] == true) { + return { + 'success': true, + 'message': data['message'] ?? 'Booking berhasil dibuat', + 'data': data['data'], + }; + } + // Menangani respons gagal (termasuk jadwal tidak tersedia) + else { + return { + 'success': false, + 'message': data['message'] ?? 'Gagal membuat booking', + 'data': data['data'], + 'status_code': response.statusCode, + }; + } + } catch (e, stackTrace) { + print('ERROR: Gagal membuat booking: $e'); + print('Stack trace: $stackTrace'); + return { + 'success': false, + 'message': 'Error: $e', + }; + } + } + + static Future> rateBooking( + int bookingId, int rating, String review) async { + try { + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Unauthenticated: Token tidak ditemukan. Silakan login kembali.', + 'error_type': 'auth_error' + }; + } + + print('DEBUG: Sending rating $rating for booking #$bookingId'); + print('DEBUG: Review text: $review'); + print( + 'DEBUG: API URL: ${ApiService.baseUrl}/bookings/$bookingId/rate'); + + final response = await http.post( + Uri.parse('${ApiService.baseUrl}/bookings/$bookingId/rate'), + headers: { + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: jsonEncode({ + 'rating': rating, + 'review': review, + }), + ); + + print('DEBUG: Response status code: ${response.statusCode}'); + print('DEBUG: Response body: ${response.body}'); + + final data = json.decode(response.body); + + // Handle authentication errors + if (response.statusCode == 401) { + return { + 'success': false, + 'message': 'Unauthenticated: Sesi login Anda telah berakhir. Silakan login kembali.', + 'error_type': 'auth_error' + }; + } + + // Handle validation errors + if (response.statusCode == 422) { + return { + 'success': false, + 'message': data['message'] ?? 'Validasi gagal. Pastikan rating dan ulasan sudah benar.', + 'error_type': 'validation_error', + 'errors': data['errors'] + }; + } + + return { + 'success': response.statusCode == 200 && data['success'] == true, + 'message': + data['message'] ?? 'Terjadi kesalahan saat memberikan rating', + 'data': data['data'], + }; + } catch (e, stackTrace) { + print('ERROR: Gagal memberikan rating: $e'); + print('Stack trace: $stackTrace'); + return { + 'success': false, + 'message': 'Error: $e', + }; + } + } + + static Future> completeBooking( + int bookingId, + String completionNotes, + String? completionPhoto, + String? pickupDate, + ) async { + try { + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan', + }; + } + + print('DEBUG: Menyelesaikan booking #$bookingId'); + print('DEBUG: Completion notes: $completionNotes'); + print('DEBUG: Completion photo: $completionPhoto'); + print('DEBUG: Pickup date: $pickupDate'); + + // Gunakan MultipartRequest untuk upload file + final request = http.MultipartRequest( + 'POST', + Uri.parse('${ApiService.baseUrl}/bookings/$bookingId/complete'), + ); + + // Tambahkan headers + request.headers.addAll({ + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + }); + + // Tambahkan fields + request.fields['completion_notes'] = completionNotes; + if (pickupDate != null) { + request.fields['pickup_date'] = pickupDate; + } + + // Tambahkan file foto jika ada + if (completionPhoto != null) { + request.files.add( + await http.MultipartFile.fromPath( + 'completion_photo', + completionPhoto, + ), + ); + } + + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + print('DEBUG: Response status code: ${response.statusCode}'); + print('DEBUG: Response body: ${response.body}'); + + final data = json.decode(response.body); + + return { + 'success': response.statusCode == 200 && data['success'] == true, + 'message': + data['message'] ?? 'Terjadi kesalahan saat menyelesaikan pesanan', + 'data': data['data'], + }; + } catch (e, stackTrace) { + print('ERROR: Gagal menyelesaikan pesanan: $e'); + print('Stack trace: $stackTrace'); + return { + 'success': false, + 'message': 'Error: $e', + }; + } + } +} diff --git a/TA_android/lib/core/services/forgot_passowrd_service.dart b/TA_android/lib/core/services/forgot_passowrd_service.dart new file mode 100644 index 0000000..f151f18 --- /dev/null +++ b/TA_android/lib/core/services/forgot_passowrd_service.dart @@ -0,0 +1,139 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +// ignore_for_file: avoid_print + +class ForgotPasswordService { + final String baseUrl = dotenv.env['API_BASE_URL'] ?? ''; + + // Service untuk forgot password customer + Future> forgotPasswordCustomer(String email) async { + try { + final response = await http.post( + Uri.parse('$baseUrl/pelanggan/forgot-password'), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({'email': email}), + ); + + final result = jsonDecode(response.body); + return { + 'success': result['success'] ?? false, + 'message': result['message'] ?? 'Terjadi kesalahan', + }; + } catch (e) { + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Service untuk reset password customer + Future> resetPasswordCustomer({ + required String email, + required String password, + required String passwordConfirmation, + required String pin, + }) async { + try { + print( + 'DEBUG: Sending reset password request to: $baseUrl/pelanggan/reset-password'); + print('DEBUG: Request payload:'); + print(jsonEncode({ + 'email': email, + 'password': '[HIDDEN]', + 'password_confirmation': '[HIDDEN]', + 'pin': pin, + })); + + final response = await http.post( + Uri.parse('$baseUrl/pelanggan/reset-password'), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({ + 'email': email, + 'password': password, + 'password_confirmation': passwordConfirmation, + 'pin': pin, + }), + ); + + print('DEBUG: Response status code: ${response.statusCode}'); + print('DEBUG: Response body: ${response.body}'); + + final result = jsonDecode(response.body); + + // Return semua informasi yang mungkin berguna + return { + 'success': result['success'] ?? false, + 'message': result['message'] ?? 'Terjadi kesalahan', + 'data': result['data'], + 'errors': result['errors'], + 'status_code': response.statusCode, + 'raw_response': response.body, + }; + } catch (e, stackTrace) { + print('ERROR: Exception during reset password request: $e'); + print('ERROR: Stack trace: $stackTrace'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + 'errors': {'exception': e.toString()}, + 'status_code': 500, + }; + } + } + + // Service untuk forgot password tailor + Future> forgotPasswordTailor(String email) async { + try { + final response = await http.post( + Uri.parse('$baseUrl/penjahit/forgot-password'), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({'email': email}), + ); + + final result = jsonDecode(response.body); + return { + 'success': result['success'] ?? false, + 'message': result['message'] ?? 'Terjadi kesalahan', + }; + } catch (e) { + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Service untuk reset password tailor + Future> resetPasswordTailor({ + required String email, + required String password, + required String passwordConfirmation, + required String pin, + }) async { + try { + final response = await http.post( + Uri.parse('$baseUrl/penjahit/reset-password'), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode({ + 'email': email, + 'password': password, + 'password_confirmation': passwordConfirmation, + 'pin': pin, + }), + ); + + final result = jsonDecode(response.body); + return { + 'success': result['success'] ?? false, + 'message': result['message'] ?? 'Terjadi kesalahan', + }; + } catch (e) { + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } +} diff --git a/TA_android/lib/core/services/midtrans_service.dart b/TA_android/lib/core/services/midtrans_service.dart new file mode 100644 index 0000000..adc2a4e --- /dev/null +++ b/TA_android/lib/core/services/midtrans_service.dart @@ -0,0 +1,195 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'dart:math'; +import 'package:flutter/material.dart'; +import 'api_service.dart'; +// ignore_for_file: avoid_print + +class MidtransService { + // Konfigurasi Midtrans + static const String clientKey = 'SB-Mid-client-I_7aBDvvdRAJ3zSI'; + static const String serverKey = 'SB-Mid-server-m_cMr-8mOqJoaorKXpXoWBoQ'; + static const String transactionCode = 'G467202065'; + + // Base URL untuk API + static final String baseUrl = ApiService.baseUrl; + + // Fungsi helper untuk mendapatkan access token + static Future getAccessToken() async { + final token = await ApiService.getToken(); + if (token == null) { + throw Exception('Token tidak ditemukan, silakan login kembali'); + } + return token; + } + + // Metode untuk memeriksa status pembayaran + static Future> checkPaymentStatus(int bookingId) async { + print('DEBUG: MidtransService.checkPaymentStatus() - Checking payment status for booking #$bookingId'); + + try { + final response = await http.get( + Uri.parse('$baseUrl/bookings/$bookingId/payment-status'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ${await getAccessToken()}', + }, + ); + + print('DEBUG: MidtransService.checkPaymentStatus() - Response status code: ${response.statusCode}'); + print('DEBUG: MidtransService.checkPaymentStatus() - Response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + final jsonResponse = json.decode(response.body); + + if (response.statusCode == 200) { + // Log respons sukses + print('DEBUG: MidtransService.checkPaymentStatus() - Success! Payment status: ${jsonResponse['data']['payment_status']}'); + return { + 'success': true, + 'data': jsonResponse['data'], + 'message': jsonResponse['message'] ?? 'Berhasil mendapatkan status pembayaran', + }; + } else { + // Log respons error + print('DEBUG: MidtransService.checkPaymentStatus() - API Error: ${jsonResponse['message']}'); + return { + 'success': false, + 'message': jsonResponse['message'] ?? 'Gagal memeriksa status pembayaran', + }; + } + } catch (e) { + // Log error + print('ERROR: MidtransService.checkPaymentStatus() - Exception: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Metode untuk menginisiasi pembayaran + static Future> initiatePayment(int bookingId) async { + print('DEBUG: MidtransService.initiatePayment() - Initiating payment for booking #$bookingId'); + + try { + final response = await http.post( + Uri.parse('$baseUrl/bookings/$bookingId/midtrans/pay'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ${await getAccessToken()}', + }, + ); + + print('DEBUG: MidtransService.initiatePayment() - Response status code: ${response.statusCode}'); + print('DEBUG: MidtransService.initiatePayment() - Response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + final jsonResponse = json.decode(response.body); + + if (response.statusCode == 200) { + print('DEBUG: MidtransService.initiatePayment() - Success! Response data: ${jsonResponse['data']}'); + return { + 'success': true, + 'data': jsonResponse['data'], + 'message': jsonResponse['message'] ?? 'Berhasil menginisiasi pembayaran', + }; + } else { + print('DEBUG: MidtransService.initiatePayment() - API Error: ${jsonResponse['message']}'); + return { + 'success': false, + 'message': jsonResponse['message'] ?? 'Gagal menginisiasi pembayaran', + }; + } + } catch (e) { + print('ERROR: MidtransService.initiatePayment() - Exception: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Konversi status pembayaran ke teks yang user-friendly + static String getPaymentStatusText(String status) { + switch (status.toLowerCase()) { + case 'unpaid': + return 'Belum Dibayar'; + case 'pending': + return 'Pembayaran Diproses'; + case 'paid': + return 'Pembayaran Berhasil'; + case 'success': + return 'Pembayaran Sukses'; + case 'failed': + return 'Pembayaran Gagal'; + case 'expired': + return 'Pembayaran Kadaluarsa'; + case 'cancelled': + return 'Pembayaran Dibatalkan'; + default: + return 'Status Tidak Diketahui'; + } + } + + // Dapatkan warna berdasarkan status pembayaran + static Color getPaymentStatusColor(String status) { + switch (status.toLowerCase()) { + case 'unpaid': + return const Color(0xFF9AA0A6); // Abu-abu + case 'pending': + return const Color(0xFFFFA000); // Orange + case 'paid': + case 'success': + return const Color(0xFF34A853); // Hijau + case 'failed': + case 'expired': + case 'cancelled': + return const Color(0xFFEA4335); // Merah + default: + return const Color(0xFF9AA0A6); // Abu-abu + } + } + + // Metode untuk memeriksa status pembayaran secara manual + static Future> checkPaymentStatusManual(int bookingId) async { + print('DEBUG: MidtransService.checkPaymentStatusManual() - Checking payment status for booking #$bookingId'); + + try { + final response = await http.post( + Uri.parse('$baseUrl/bookings/$bookingId/payment-status/check'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ${await getAccessToken()}', + }, + ); + + print('DEBUG: MidtransService.checkPaymentStatusManual() - Response status code: ${response.statusCode}'); + print('DEBUG: MidtransService.checkPaymentStatusManual() - Response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + final jsonResponse = json.decode(response.body); + + if (response.statusCode == 200) { + print('DEBUG: MidtransService.checkPaymentStatusManual() - Success! Payment status: ${jsonResponse['data']['payment_status']}'); + return { + 'success': true, + 'data': jsonResponse['data'], + 'message': jsonResponse['message'] ?? 'Status pembayaran berhasil diperbarui', + }; + } else { + print('DEBUG: MidtransService.checkPaymentStatusManual() - API Error: ${jsonResponse['message']}'); + return { + 'success': false, + 'message': jsonResponse['message'] ?? 'Gagal memeriksa status pembayaran', + }; + } + } catch (e) { + print('ERROR: MidtransService.checkPaymentStatusManual() - Exception: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } +} diff --git a/TA_android/lib/core/services/midtrans_service.dart.bak b/TA_android/lib/core/services/midtrans_service.dart.bak new file mode 100644 index 0000000..5fa9dbf --- /dev/null +++ b/TA_android/lib/core/services/midtrans_service.dart.bak @@ -0,0 +1,152 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'dart:math'; +import 'package:flutter/material.dart'; +import 'api_service.dart'; + +class MidtransService { + // Konfigurasi Midtrans + static const String clientKey = 'SB-Mid-client-R_h8dtZUuy1pK8fn'; + static const String serverKey = 'SB-Mid-server-yOklCwe5I_63lC5lDN3k8Kyw'; + static const String transactionCode = 'G937265596'; + + // Base URL untuk API + static final String baseUrl = ApiService.baseUrl; + + // Fungsi helper untuk mendapatkan access token + static Future getAccessToken() async { + final token = await ApiService.getToken(); + if (token == null) { + throw Exception('Token tidak ditemukan, silakan login kembali'); + } + return token; + } + + // Metode untuk memeriksa status pembayaran + static Future> checkPaymentStatus(int bookingId) async { + print('DEBUG: MidtransService.checkPaymentStatus() - Checking payment status for booking #$bookingId'); + + try { + final response = await http.get( + Uri.parse('$baseUrl/bookings/$bookingId/payment-status'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ${await getAccessToken()}', + }, + ); + + print('DEBUG: MidtransService.checkPaymentStatus() - Response status code: ${response.statusCode}'); + print('DEBUG: MidtransService.checkPaymentStatus() - Response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + final jsonResponse = json.decode(response.body); + + if (response.statusCode == 200) { + // Log respons sukses + print('DEBUG: MidtransService.checkPaymentStatus() - Success! Payment status: ${jsonResponse['data']['payment_status']}'); + return { + 'success': true, + 'data': jsonResponse['data'], + 'message': jsonResponse['message'] ?? 'Berhasil mendapatkan status pembayaran', + }; + } else { + // Log respons error + print('DEBUG: MidtransService.checkPaymentStatus() - API Error: ${jsonResponse['message']}'); + return { + 'success': false, + 'message': jsonResponse['message'] ?? 'Gagal memeriksa status pembayaran', + }; + } + } catch (e) { + // Log error + print('ERROR: MidtransService.checkPaymentStatus() - Exception: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Metode untuk menginisiasi pembayaran + static Future> initiatePayment(int bookingId) async { + print('DEBUG: MidtransService.initiatePayment() - Initiating payment for booking #$bookingId'); + + try { + final response = await http.post( + Uri.parse('$baseUrl/bookings/$bookingId/midtrans/pay'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ${await getAccessToken()}', + }, + ); + + print('DEBUG: MidtransService.initiatePayment() - Response status code: ${response.statusCode}'); + print('DEBUG: MidtransService.initiatePayment() - Response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + final jsonResponse = json.decode(response.body); + + if (response.statusCode == 200) { + print('DEBUG: MidtransService.initiatePayment() - Success! Response data: ${jsonResponse['data']}'); + return { + 'success': true, + 'data': jsonResponse['data'], + 'message': jsonResponse['message'] ?? 'Berhasil menginisiasi pembayaran', + }; + } else { + print('DEBUG: MidtransService.initiatePayment() - API Error: ${jsonResponse['message']}'); + return { + 'success': false, + 'message': jsonResponse['message'] ?? 'Gagal menginisiasi pembayaran', + }; + } + } catch (e) { + print('ERROR: MidtransService.initiatePayment() - Exception: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Konversi status pembayaran ke teks yang user-friendly + static String getPaymentStatusText(String status) { + switch (status.toLowerCase()) { + case 'unpaid': + return 'Belum Dibayar'; + case 'pending': + return 'Pembayaran Diproses'; + case 'paid': + return 'Pembayaran Berhasil'; + case 'success': + return 'Pembayaran Sukses'; + case 'failed': + return 'Pembayaran Gagal'; + case 'expired': + return 'Pembayaran Kadaluarsa'; + case 'cancelled': + return 'Pembayaran Dibatalkan'; + default: + return 'Status Tidak Diketahui'; + } + } + + // Dapatkan warna berdasarkan status pembayaran + static Color getPaymentStatusColor(String status) { + switch (status.toLowerCase()) { + case 'unpaid': + return const Color(0xFF9AA0A6); // Abu-abu + case 'pending': + return const Color(0xFFFFA000); // Orange + case 'paid': + case 'success': + return const Color(0xFF34A853); // Hijau + case 'failed': + case 'expired': + case 'cancelled': + return const Color(0xFFEA4335); // Merah + default: + return const Color(0xFF9AA0A6); // Abu-abu + } + } +} diff --git a/TA_android/lib/core/services/midtrans_service.dart.temp b/TA_android/lib/core/services/midtrans_service.dart.temp new file mode 100644 index 0000000..5fa9dbf --- /dev/null +++ b/TA_android/lib/core/services/midtrans_service.dart.temp @@ -0,0 +1,152 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'dart:math'; +import 'package:flutter/material.dart'; +import 'api_service.dart'; + +class MidtransService { + // Konfigurasi Midtrans + static const String clientKey = 'SB-Mid-client-R_h8dtZUuy1pK8fn'; + static const String serverKey = 'SB-Mid-server-yOklCwe5I_63lC5lDN3k8Kyw'; + static const String transactionCode = 'G937265596'; + + // Base URL untuk API + static final String baseUrl = ApiService.baseUrl; + + // Fungsi helper untuk mendapatkan access token + static Future getAccessToken() async { + final token = await ApiService.getToken(); + if (token == null) { + throw Exception('Token tidak ditemukan, silakan login kembali'); + } + return token; + } + + // Metode untuk memeriksa status pembayaran + static Future> checkPaymentStatus(int bookingId) async { + print('DEBUG: MidtransService.checkPaymentStatus() - Checking payment status for booking #$bookingId'); + + try { + final response = await http.get( + Uri.parse('$baseUrl/bookings/$bookingId/payment-status'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ${await getAccessToken()}', + }, + ); + + print('DEBUG: MidtransService.checkPaymentStatus() - Response status code: ${response.statusCode}'); + print('DEBUG: MidtransService.checkPaymentStatus() - Response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + final jsonResponse = json.decode(response.body); + + if (response.statusCode == 200) { + // Log respons sukses + print('DEBUG: MidtransService.checkPaymentStatus() - Success! Payment status: ${jsonResponse['data']['payment_status']}'); + return { + 'success': true, + 'data': jsonResponse['data'], + 'message': jsonResponse['message'] ?? 'Berhasil mendapatkan status pembayaran', + }; + } else { + // Log respons error + print('DEBUG: MidtransService.checkPaymentStatus() - API Error: ${jsonResponse['message']}'); + return { + 'success': false, + 'message': jsonResponse['message'] ?? 'Gagal memeriksa status pembayaran', + }; + } + } catch (e) { + // Log error + print('ERROR: MidtransService.checkPaymentStatus() - Exception: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Metode untuk menginisiasi pembayaran + static Future> initiatePayment(int bookingId) async { + print('DEBUG: MidtransService.initiatePayment() - Initiating payment for booking #$bookingId'); + + try { + final response = await http.post( + Uri.parse('$baseUrl/bookings/$bookingId/midtrans/pay'), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': 'Bearer ${await getAccessToken()}', + }, + ); + + print('DEBUG: MidtransService.initiatePayment() - Response status code: ${response.statusCode}'); + print('DEBUG: MidtransService.initiatePayment() - Response body: ${response.body.substring(0, min(200, response.body.length))}...'); + + final jsonResponse = json.decode(response.body); + + if (response.statusCode == 200) { + print('DEBUG: MidtransService.initiatePayment() - Success! Response data: ${jsonResponse['data']}'); + return { + 'success': true, + 'data': jsonResponse['data'], + 'message': jsonResponse['message'] ?? 'Berhasil menginisiasi pembayaran', + }; + } else { + print('DEBUG: MidtransService.initiatePayment() - API Error: ${jsonResponse['message']}'); + return { + 'success': false, + 'message': jsonResponse['message'] ?? 'Gagal menginisiasi pembayaran', + }; + } + } catch (e) { + print('ERROR: MidtransService.initiatePayment() - Exception: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Konversi status pembayaran ke teks yang user-friendly + static String getPaymentStatusText(String status) { + switch (status.toLowerCase()) { + case 'unpaid': + return 'Belum Dibayar'; + case 'pending': + return 'Pembayaran Diproses'; + case 'paid': + return 'Pembayaran Berhasil'; + case 'success': + return 'Pembayaran Sukses'; + case 'failed': + return 'Pembayaran Gagal'; + case 'expired': + return 'Pembayaran Kadaluarsa'; + case 'cancelled': + return 'Pembayaran Dibatalkan'; + default: + return 'Status Tidak Diketahui'; + } + } + + // Dapatkan warna berdasarkan status pembayaran + static Color getPaymentStatusColor(String status) { + switch (status.toLowerCase()) { + case 'unpaid': + return const Color(0xFF9AA0A6); // Abu-abu + case 'pending': + return const Color(0xFFFFA000); // Orange + case 'paid': + case 'success': + return const Color(0xFF34A853); // Hijau + case 'failed': + case 'expired': + case 'cancelled': + return const Color(0xFFEA4335); // Merah + default: + return const Color(0xFF9AA0A6); // Abu-abu + } + } +} diff --git a/TA_android/lib/core/services/profile_service.dart b/TA_android/lib/core/services/profile_service.dart new file mode 100644 index 0000000..8289ffd --- /dev/null +++ b/TA_android/lib/core/services/profile_service.dart @@ -0,0 +1,211 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:http/http.dart' as http; +import '../utils/logger.dart'; +import 'api_service.dart'; + +class ProfileService { + static Future> getProfile() async { + try { + AppLogger.info('Memuat data profil dari API', tag: 'Profile'); + + // Gunakan ApiResponse untuk respons terstruktur + final apiResponse = await ApiService.get('/profile'); + + if (apiResponse.isSuccess) { + AppLogger.info('Data profil berhasil dimuat', tag: 'Profile'); + return { + 'success': true, + 'data': apiResponse.data, + 'message': apiResponse.message, + }; + } else { + AppLogger.error('Gagal memuat profil: ${apiResponse.message}', + tag: 'Profile'); + return { + 'success': false, + 'message': apiResponse.message, + }; + } + } catch (e) { + AppLogger.error('Exception saat memuat profil', error: e, tag: 'Profile'); + return { + 'success': false, + 'message': 'Terjadi kesalahan saat memuat profil: $e', + }; + } + } + + /// Upload foto profil untuk user (pelanggan atau penjahit) + /// Menggunakan endpoint: POST /profile/photo + static Future> uploadProfilePhoto(File photo) async { + try { + AppLogger.info('Mulai upload foto profil', tag: 'ProfilePhoto'); + AppLogger.debug('File path: ${photo.path}', tag: 'ProfilePhoto'); + + // Pastikan file ada + if (!photo.existsSync()) { + AppLogger.error('File foto tidak ditemukan di path: ${photo.path}', + tag: 'ProfilePhoto'); + return { + 'success': false, + 'message': 'File foto tidak ditemukan', + }; + } + + // Dapatkan token untuk otorisasi + final token = await ApiService.getToken(); + if (token == null) { + AppLogger.error('Token tidak ditemukan, tidak dapat upload foto', + tag: 'ProfilePhoto'); + return { + 'success': false, + 'message': 'Anda perlu login untuk mengupload foto profil', + }; + } + + // Buat request multipart + final uri = Uri.parse('${ApiService.baseUrl}/profile/photo'); + final request = http.MultipartRequest('POST', uri); + + // Tambahkan header otorisasi + request.headers.addAll({ + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + }); + + AppLogger.debug('URL endpoint: $uri', tag: 'ProfilePhoto'); + AppLogger.debug('Headers: ${request.headers}', tag: 'ProfilePhoto'); + + // Tambahkan file foto + final fileName = photo.path.split('/').last; + final fileStream = http.ByteStream(photo.openRead()); + final fileLength = await photo.length(); + + AppLogger.debug('Nama file: $fileName', tag: 'ProfilePhoto'); + AppLogger.debug('Ukuran file: $fileLength bytes', tag: 'ProfilePhoto'); + + final multipartFile = http.MultipartFile( + 'profile_photo', // nama field yang diharapkan oleh API + fileStream, + fileLength, + filename: fileName, + ); + + request.files.add(multipartFile); + + // Kirim request + AppLogger.info('Mengirim request upload foto profil', + tag: 'ProfilePhoto'); + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + AppLogger.api( + 'Response status upload foto profil: ${response.statusCode}', + tag: 'ProfilePhoto'); + AppLogger.api('Response body upload foto profil: ${response.body}', + tag: 'ProfilePhoto'); + + // Parse response + final Map responseData = json.decode(response.body); + + if (response.statusCode == 200) { + AppLogger.info('Foto profil berhasil diupload', tag: 'ProfilePhoto'); + return { + 'success': true, + 'message': responseData['message'] ?? 'Foto profil berhasil diupload', + 'data': responseData['data'], + }; + } else { + AppLogger.error( + 'Gagal mengupload foto profil: ${responseData['message']}', + tag: 'ProfilePhoto'); + return { + 'success': false, + 'message': responseData['message'] ?? 'Gagal mengupload foto profil', + 'errors': responseData['errors'], + }; + } + } catch (e) { + AppLogger.error('Exception saat upload foto profil', + error: e, tag: 'ProfilePhoto'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Method helper untuk mendapatkan URL lengkap foto profil + static String getFullProfilePhotoUrl(String? photoUrl) { + if (photoUrl == null || photoUrl.isEmpty) { + return ''; + } + + return ApiService.getFullImageUrl(photoUrl); + } + + static Future> updateProfile( + Map userData) async { + try { + AppLogger.info('Memulai update profil', tag: 'ProfileService'); + AppLogger.debug('Data yang akan diupdate: $userData', + tag: 'ProfileService'); + + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan. Silakan login kembali.' + }; + } + + // Gunakan ApiService.baseUrl yang sudah terkonfigurasi + final uri = Uri.parse('${ApiService.baseUrl}/profile'); + AppLogger.debug('URL: $uri', tag: 'ProfileService'); + AppLogger.debug('Token: $token', tag: 'ProfileService'); + + final response = await http.post( + uri, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: json.encode(userData), + ); + + AppLogger.debug('Response status: ${response.statusCode}', + tag: 'ProfileService'); + AppLogger.debug('Response body: ${response.body}', tag: 'ProfileService'); + + final responseData = json.decode(response.body); + + if (response.statusCode == 200) { + AppLogger.info('Profil berhasil diperbarui', tag: 'ProfileService'); + return { + 'success': true, + 'message': responseData['message'] ?? 'Profil berhasil diperbarui', + 'data': responseData['data'], + }; + } else { + final errorMessage = + responseData['message'] ?? 'Gagal memperbarui profil'; + AppLogger.error('Gagal memperbarui profil: $errorMessage', + tag: 'ProfileService'); + return { + 'success': false, + 'message': errorMessage, + 'errors': responseData['errors'], + }; + } + } catch (e) { + AppLogger.error('Exception saat update profil', + error: e, tag: 'ProfileService'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } +} diff --git a/TA_android/lib/core/services/search_service.dart b/TA_android/lib/core/services/search_service.dart new file mode 100644 index 0000000..3f379d0 --- /dev/null +++ b/TA_android/lib/core/services/search_service.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import '../models/tailor_model.dart'; +import '../utils/logger.dart'; +import 'api_service.dart'; + +class SearchService { + final String _baseUrl = ApiService.baseUrl.substring(0, ApiService.baseUrl.lastIndexOf('/api')); + + Future> searchTailors(String query) async { + try { + AppLogger.info('Memulai pencarian penjahit', tag: 'SearchService'); + final endpoint = '$_baseUrl/api/tailors/search/name/$query'; + AppLogger.debug('URL: $endpoint', tag: 'SearchService'); + + final response = await http.get(Uri.parse(endpoint)).timeout( + const Duration(seconds: 5), + ); + + AppLogger.debug('Status code: ${response.statusCode}', tag: 'SearchService'); + AppLogger.debug('Response body: ${response.body}', tag: 'SearchService'); + + if (response.statusCode == 200) { + final Map responseData = json.decode(response.body); + + if (responseData['success'] == true && responseData['data'] != null) { + final List tailorsData = responseData['data']['tailors']; + final results = + tailorsData.map((json) => TailorModel.fromJson(json)).toList(); + + AppLogger.info( + 'Berhasil mendapatkan ${results.length} hasil pencarian', + tag: 'SearchService'); + return results; + } else { + AppLogger.warning('Response sukses tapi tidak ada data penjahit', + tag: 'SearchService'); + return []; + } + } else { + AppLogger.error('Error searching tailors: ${response.statusCode}', + error: response.body, tag: 'SearchService'); + throw Exception('Gagal mencari penjahit'); + } + } on http.ClientException catch (e) { + AppLogger.error('Client error while searching tailors', + error: e.toString(), tag: 'SearchService'); + throw Exception('Terjadi kesalahan jaringan saat mencari penjahit'); + } on Exception catch (e) { + AppLogger.error('Error while searching tailors', + error: e.toString(), tag: 'SearchService'); + throw Exception('Terjadi kesalahan saat mencari penjahit'); + } + } +} diff --git a/TA_android/lib/core/services/shared_prefs_helper.dart b/TA_android/lib/core/services/shared_prefs_helper.dart new file mode 100644 index 0000000..768b9d5 --- /dev/null +++ b/TA_android/lib/core/services/shared_prefs_helper.dart @@ -0,0 +1,95 @@ +import 'package:shared_preferences/shared_preferences.dart'; +// ignore_for_file: avoid_print + +/// Helper class untuk mengelola SharedPreferences dengan debugging yang lebih baik +class SharedPrefsHelper { + static const String TOKEN_KEY = 'auth_token'; + + /// Memeriksa apakah SharedPreferences berfungsi dengan benar + static Future checkIfWorking() async { + try { + print('DEBUG: Memeriksa apakah SharedPreferences berfungsi...'); + + // Coba mendapatkan instance + final prefs = await SharedPreferences.getInstance(); + print('DEBUG: SharedPreferences instance berhasil dibuat'); + + // Coba menyimpan test value + final testKey = 'test_key_${DateTime.now().millisecondsSinceEpoch}'; + final testValue = 'test_value_${DateTime.now().millisecondsSinceEpoch}'; + + final saveResult = await prefs.setString(testKey, testValue); + print('DEBUG: Hasil menyimpan test key: $saveResult'); + + if (!saveResult) { + print('ERROR: Gagal menyimpan test key'); + return false; + } + + // Coba membaca test value + final retrievedValue = prefs.getString(testKey); + print('DEBUG: Nilai yang dibaca: $retrievedValue'); + + if (retrievedValue != testValue) { + print( + 'ERROR: Nilai yang dibaca tidak sama dengan nilai yang disimpan!'); + return false; + } + + // Coba menghapus test value + final removeResult = await prefs.remove(testKey); + print('DEBUG: Hasil menghapus test key: $removeResult'); + + print('DEBUG: SharedPreferences berfungsi dengan baik!'); + return true; + } catch (e) { + print('ERROR KRITIS pada SharedPreferences: $e'); + return false; + } + } + + /// Mencoba memperbaiki SharedPreferences jika ada masalah + static Future tryToFix() async { + try { + print('DEBUG: Mencoba memperbaiki SharedPreferences...'); + + // Coba clear semua data dalam shared preferences + final prefs = await SharedPreferences.getInstance(); + final clearResult = await prefs.clear(); + + print('DEBUG: Clear SharedPreferences result: $clearResult'); + + // Coba test lagi + return await checkIfWorking(); + } catch (e) { + print('ERROR: Gagal memperbaiki SharedPreferences: $e'); + return false; + } + } + + /// Solusi fallback jika shared preferences bermasalah + static final Map _memoryStorage = {}; + + /// Menyimpan token ke memory jika shared preferences bermasalah + static void saveTokenToMemory(String token) { + _memoryStorage[TOKEN_KEY] = token; + print('DEBUG: Token disimpan ke memory: ${token.substring(0, 10)}...'); + } + + /// Mengambil token dari memory jika shared preferences bermasalah + static String? getTokenFromMemory() { + final token = _memoryStorage[TOKEN_KEY]; + if (token != null) { + print('DEBUG: Token diambil dari memory: ${token.substring(0, 10)}...'); + } else { + print('DEBUG: Token tidak ditemukan di memory'); + } + return token; + } + + /// Menghapus token dari memory + static void removeTokenFromMemory() { + _memoryStorage.remove(TOKEN_KEY); + print('DEBUG: Token dihapus dari memory'); + } +} diff --git a/TA_android/lib/core/services/wallet_wd_service.dart b/TA_android/lib/core/services/wallet_wd_service.dart new file mode 100644 index 0000000..05b5447 --- /dev/null +++ b/TA_android/lib/core/services/wallet_wd_service.dart @@ -0,0 +1,265 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'api_service.dart'; +// ignore_for_file: avoid_print + +class WalletWDService { + static final String baseUrl = ApiService.baseUrl; + + // Mendapatkan informasi wallet + static Future> getWalletInfo() async { + try { + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan', + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/wallet'), + headers: { + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + }, + ); + + final data = json.decode(response.body); + + if (response.statusCode == 200) { + return { + 'success': true, + 'data': data['data'], + 'message': data['message'], + }; + } + + return { + 'success': false, + 'message': data['message'] ?? 'Gagal mendapatkan informasi wallet', + }; + } catch (e) { + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Mendapatkan daftar akun bank + static Future> getBankAccounts() async { + try { + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan', + }; + } + + final response = await http.get( + Uri.parse('$baseUrl/bank-accounts'), + headers: { + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + }, + ); + + final data = json.decode(response.body); + + if (response.statusCode == 200) { + return { + 'success': true, + 'data': data['data'], + 'message': data['message'], + }; + } + + return { + 'success': false, + 'message': data['message'] ?? 'Gagal mendapatkan daftar akun bank', + }; + } catch (e) { + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Mendaftarkan akun bank baru + static Future> registerBankAccount({ + required String bankName, + required String accountNumber, + required String accountHolderName, + }) async { + try { + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan', + }; + } + + final response = await http.post( + Uri.parse('$baseUrl/bank-accounts'), + headers: { + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: json.encode({ + 'bank_name': bankName, + 'account_number': accountNumber, + 'account_holder_name': accountHolderName, + }), + ); + + final data = json.decode(response.body); + + if (response.statusCode == 200) { + return { + 'success': true, + 'data': data['data'], + 'message': data['message'], + }; + } + + return { + 'success': false, + 'message': data['message'] ?? 'Gagal mendaftarkan akun bank', + 'errors': data['data'], + }; + } catch (e) { + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Meminta penarikan dana + static Future> requestWithdrawal({ + required int bankAccountId, + required double amount, + }) async { + try { + final token = await ApiService.getToken(); + if (token == null) { + return { + 'success': false, + 'message': 'Token tidak ditemukan', + }; + } + + final response = await http.post( + Uri.parse('$baseUrl/withdrawals'), + headers: { + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: json.encode({ + 'bank_account_id': bankAccountId, + 'amount': amount, + }), + ); + + final data = json.decode(response.body); + + // Log respons untuk debugging + print('requestWithdrawal response: ${response.body}'); + + if (response.statusCode == 200) { + // Pastikan kita mengembalikan data lengkap termasuk info wallet yang diperbarui + return { + 'success': true, + 'data': data['data'], // Berisi 'withdrawal' dan 'wallet' + 'message': data['message'], + }; + } + + // Handle untuk insufficient balance error + return { + 'success': false, + 'message': data['message'] ?? 'Gagal meminta penarikan dana', + 'errors': data['data'], + 'wallet_info': data['data'], // Mungkin berisi info wallet saat gagal + }; + } catch (e) { + print('requestWithdrawal error: $e'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + }; + } + } + + // Mendapatkan riwayat penarikan dana + static Future> getWithdrawalHistory({String? status}) async { + try { + print('Start getWithdrawalHistory - Status filter: $status'); + + final token = await ApiService.getToken(); + if (token == null) { + print('getWithdrawalHistory: Token tidak ditemukan'); + return { + 'success': false, + 'message': 'Token tidak ditemukan', + }; + } + + // Build URL with query parameter if status is provided + String url = '$baseUrl/withdrawals'; + if (status != null && status.isNotEmpty) { + url += '?status=$status'; + } + + print('getWithdrawalHistory: URL request: $url'); + print('getWithdrawalHistory: Token: ${token.substring(0, 10)}...'); + + final response = await http.get( + Uri.parse(url), + headers: { + 'Authorization': 'Bearer $token', + 'Accept': 'application/json', + }, + ); + + print('getWithdrawalHistory: Status code: ${response.statusCode}'); + print('getWithdrawalHistory: Response body: ${response.body}'); + + final data = json.decode(response.body); + + if (response.statusCode == 200) { + final result = { + 'success': true, + 'data': data['data'], + 'message': data['message'], + 'raw_response': response.body, // Include raw response for debugging + }; + + print('getWithdrawalHistory: Success, data count: ${(data['data'] as List?)?.length ?? 0}'); + return result; + } + + print('getWithdrawalHistory: Failed with message: ${data['message']}'); + return { + 'success': false, + 'message': data['message'] ?? 'Gagal mendapatkan riwayat penarikan', + 'raw_response': response.body, // Include raw response for debugging + }; + } catch (e, stackTrace) { + print('getWithdrawalHistory: Exception: $e'); + print('getWithdrawalHistory: Stack trace: $stackTrace'); + return { + 'success': false, + 'message': 'Terjadi kesalahan: $e', + 'error': e.toString(), + 'stack_trace': stackTrace.toString(), + }; + } + } +} diff --git a/TA_android/lib/core/theme/colors.dart b/TA_android/lib/core/theme/colors.dart new file mode 100644 index 0000000..d386ee2 --- /dev/null +++ b/TA_android/lib/core/theme/colors.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + +class AppColors { + static const Color primary = Color(0xFF1A2552); + static const Color secondary = Color(0xFF34A853); + static const Color error = Color(0xFFEA4335); + static const Color warning = Color(0xFFFFA000); + static const Color info = Color(0xFF1976D2); + static const Color grey = Color(0xFF9AA0A6); + + // Prevent instantiation + AppColors._(); +} \ No newline at end of file diff --git a/TA_android/lib/core/utils/app_routes.dart b/TA_android/lib/core/utils/app_routes.dart new file mode 100644 index 0000000..d000045 --- /dev/null +++ b/TA_android/lib/core/utils/app_routes.dart @@ -0,0 +1,9 @@ +class AppRoutes { + static const String splash = '/'; + static const String login = '/login'; + static const String register = '/register'; + static const String home = '/home'; + static const String withdrawal = '/withdrawal'; + static const String walletHistory = '/wallet-history'; + static const String addBankAccount = '/add-bank-account'; +} \ No newline at end of file diff --git a/TA_android/lib/core/utils/logger.dart b/TA_android/lib/core/utils/logger.dart new file mode 100644 index 0000000..82debdc --- /dev/null +++ b/TA_android/lib/core/utils/logger.dart @@ -0,0 +1,104 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +// ignore_for_file: avoid_print + +/// Kelas utilitas untuk logging pada aplikasi +class AppLogger { + static bool _enableVerbose = false; + + /// Mengaktifkan log verbose (detail) + static void enableVerboseLogging(bool enable) { + _enableVerbose = enable; + } + + /// Log informasi umum + static void info(String message, {String? tag}) { + final logTag = tag != null ? '[$tag]' : '[INFO]'; + print('$logTag $message'); + } + + /// Log untuk debugging + static void debug(String message, {String? tag}) { + if (kDebugMode || _enableVerbose) { + final logTag = tag != null ? '[$tag]' : '[DEBUG]'; + print('$logTag $message'); + } + } + + /// Log untuk error + static void error(String message, + {Object? error, StackTrace? stackTrace, String? tag}) { + final logTag = tag != null ? '[$tag]' : '[ERROR]'; + print('$logTag $message'); + + if (error != null) { + print('$logTag Error details: $error'); + } + + if (stackTrace != null && (_enableVerbose || kDebugMode)) { + print('$logTag StackTrace: $stackTrace'); + } + } + + /// Log untuk catatan penting + static void warning(String message, {String? tag}) { + final logTag = tag != null ? '[$tag]' : '[WARNING]'; + print('$logTag $message'); + } + + /// Log untuk API request dan response + static void api(String message, {Object? data, String? tag}) { + if (kDebugMode || _enableVerbose) { + final logTag = tag != null ? '[$tag]' : '[API]'; + print('$logTag $message'); + + if (data != null) { + final String dataString = data.toString(); + // Batasi output jika terlalu panjang + if (dataString.length > 500 && !_enableVerbose) { + print( + '$logTag Data: ${dataString.substring(0, 500)}... (${dataString.length} karakter)'); + } else { + print('$logTag Data: $data'); + } + } + } + } + + /// Log khusus untuk UI events + static void ui(String message, {String? tag}) { + if (kDebugMode || _enableVerbose) { + final logTag = tag != null ? '[$tag]' : '[UI]'; + print('$logTag $message'); + } + } + + /// Log khusus untuk form dan validasi + static void form(String message, + {Map? fields, String? tag}) { + if (kDebugMode || _enableVerbose) { + final logTag = tag != null ? '[$tag]' : '[FORM]'; + print('$logTag $message'); + + if (fields != null && fields.isNotEmpty) { + print('$logTag Form fields:'); + fields.forEach((key, value) { + final valueString = value is String ? '"$value"' : value; + final isValid = + value != null && (value is String ? value.isNotEmpty : true); + print('$logTag - $key: $valueString (valid: $isValid)'); + }); + } + } + } + + /// Buat FocusNode yang melakukan logging saat fokus berubah + static FocusNode createLoggingFocusNode(String fieldName, {String? tag}) { + final node = FocusNode(); + node.addListener(() { + final status = node.hasFocus ? 'menerima fokus' : 'kehilangan fokus'; + AppLogger.ui('Field "$fieldName" $status', tag: tag ?? 'Focus'); + }); + return node; + } +} diff --git a/TA_android/lib/core/utils/url_helper.dart b/TA_android/lib/core/utils/url_helper.dart new file mode 100644 index 0000000..d8d5cc5 --- /dev/null +++ b/TA_android/lib/core/utils/url_helper.dart @@ -0,0 +1,109 @@ +import 'package:flutter_dotenv/flutter_dotenv.dart'; +// ignore_for_file: avoid_print + +/// Utilitas untuk membantu penanganan URL dalam aplikasi +class UrlHelper { + /// Base URL untuk API dari variabel lingkungan + static String get baseUrl => + dotenv.env['API_BASE_URL'] ?? 'https://api-tailorhub.stuffly.my.id/api'; + // dotenv.env['API_BASE_URL'] ?? 'http://127.0.0.1:8000/api'; + + /// Base URL untuk gambar dari variabel lingkungan + static String get imageBaseUrl => + dotenv.env['API_IMAGE_BASE_URL'] ?? 'https://api-tailorhub.stuffly.my.id/api'; + // dotenv.env['API_IMAGE_BASE_URL'] ?? 'http://127.0.0.1:8000'; + + /// Mengubah path relatif menjadi URL lengkap + static String getFullImageUrl(String? photoPath) { + if (photoPath == null || photoPath.isEmpty) { + print('UrlHelper: Photo path null atau kosong'); + return ''; + } + + // Jika sudah berupa URL lengkap, kembalikan apa adanya + if (photoPath.startsWith('http://') || photoPath.startsWith('https://')) { + print('UrlHelper: URL sudah lengkap: $photoPath'); + return photoPath; + } + + // Tambahkan base URL sesuai dengan format path + String result; + if (photoPath.startsWith('/')) { + result = '$imageBaseUrl$photoPath'; + print('UrlHelper: Converted URL dengan / di awal: $result'); + } else { + result = '$imageBaseUrl/$photoPath'; + print('UrlHelper: Converted URL tanpa / di awal: $result'); + } + + return result; + } + + /// Mengkonversi path gambar menjadi URL lengkap yang valid + static String getValidImageUrl(String? imagePath) { + if (imagePath == null || imagePath.isEmpty) return ''; + + // Jika sudah berupa URL lengkap, kembalikan apa adanya + if (imagePath.startsWith('http')) { + print('UrlHelper: URL sudah lengkap: $imagePath'); + return imagePath; + } + + // Buat path yang standar dengan menghapus / di awal jika ada + String path = imagePath; + if (path.startsWith('/')) { + path = path.substring(1); + } + + // Periksa apakah path sudah mengandung 'storage/' + if (path.startsWith('storage/')) { + // Jika sudah ada storage/, gunakan langsung + String url = '$imageBaseUrl/$path'; + print('UrlHelper: Converted URL dengan storage/ sudah ada: $url'); + return url; + } else { + // Jika tidak ada 'storage/', tambahkan + String url = '$imageBaseUrl/storage/$path'; + print('UrlHelper: Converted URL dengan penambahan storage/: $url'); + return url; + } + } + + /// Mengecek jika URL gambar profil memerlukan perbaikan + static bool needsUrlFix(String url) { + return url.contains('/storage/storage/') || + (!url.contains('/storage/') && !url.startsWith('http')); + } + + /// Mengembalikan URL gambar yang sudah diperbaiki + static String fixImageUrl(String url) { + // Jika URL sudah lengkap dengan http, kembalikan apa adanya + if (url.startsWith('http')) { + // Periksa duplikasi /storage/storage/ + if (url.contains('/storage/storage/')) { + return url.replaceAll('/storage/storage/', '/storage/'); + } + return url; + } + + // Jika tidak ada /storage/ sama sekali, tambahkan + if (!url.contains('/storage/')) { + if (url.startsWith('/')) { + return '$imageBaseUrl/storage$url'; + } else { + return '$imageBaseUrl/storage/$url'; + } + } + + // Jika sudah ada /storage/ tetapi bukan URL lengkap + if (!url.startsWith('http')) { + if (url.startsWith('/')) { + return '$imageBaseUrl$url'; + } else { + return '$imageBaseUrl/$url'; + } + } + + return url; + } +} diff --git a/TA_android/lib/core/widgets/category_card.dart b/TA_android/lib/core/widgets/category_card.dart new file mode 100644 index 0000000..5c2f7f6 --- /dev/null +++ b/TA_android/lib/core/widgets/category_card.dart @@ -0,0 +1,420 @@ +import 'package:flutter/material.dart'; +import 'dart:ui' as ui; +import 'dart:async'; +import 'package:http/http.dart' as http; +import '../services/api_service.dart'; +// ignore_for_file: avoid_print + +class CategoryCard extends StatelessWidget { + final String imagePath; + final String categoryName; + final bool isSelected; + final VoidCallback onTap; + final bool isNetworkImage; + + // Cache gambar yang berhasil dibuat + static final Map _imageCache = {}; + // Cache gambar yang gagal, untuk menghindari percobaan berulang + static final Set _failedImageUrls = {}; + + const CategoryCard({ + super.key, + required this.imagePath, + required this.categoryName, + required this.isSelected, + required this.onTap, + this.isNetworkImage = false, + }); + + @override + Widget build(BuildContext context) { + print('\n=== CategoryCard Debug Info ==='); + print('Category Name: $categoryName'); + print('Image Path: $imagePath'); + print('Is Network Image: $isNetworkImage'); + print('Selected: $isSelected'); + print('=============================\n'); + + return GestureDetector( + onTap: onTap, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: isSelected + ? const Color(0xFF1A2552).withOpacity(0.1) + : Colors.grey[200], + border: Border.all( + color: + isSelected ? const Color(0xFF1A2552) : Colors.transparent, + width: 2, + ), + ), + child: ClipOval( + child: _buildImage(), + ), + ), + const SizedBox(height: 4), + Text( + categoryName, + style: TextStyle( + fontSize: 12, + fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, + color: isSelected ? const Color(0xFF1A2552) : Colors.black, + ), + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ); + } + + Widget _buildImage() { + // Cek apakah URL sudah gagal sebelumnya + if (isNetworkImage && _failedImageUrls.contains(imagePath)) { + print('⚠️ URL gambar sudah diketahui gagal sebelumnya: $imagePath'); + return _buildDefaultCategoryIcon(); + } + + if (isNetworkImage) { + // Verifikasi URL yang valid + if (!_isValidUrl(imagePath)) { + print('⚠️ URL gambar tidak valid: $imagePath'); + _failedImageUrls.add(imagePath); + return _buildDefaultCategoryIcon(); + } + + // Gunakan FutureBuilder untuk memungkinkan lebih banyak kontrol selama loading + return FutureBuilder( + future: _fetchImage(imagePath), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: CircularProgressIndicator( + color: Color(0xFF1A2552), + strokeWidth: 2, + ), + ); + } else if (snapshot.hasError) { + print('❌ Error loading image: ${snapshot.error}'); + _failedImageUrls.add(imagePath); + return _buildDefaultCategoryIcon(); + } else if (snapshot.hasData) { + final response = snapshot.data!; + if (response.statusCode == 200) { + // Periksa content-type + final contentType = response.headers['content-type']; + if (contentType != null && contentType.startsWith('image/')) { + print('✅ Image loaded successfully: $imagePath'); + // Gunakan Image.memory untuk memuat dari bytes + return Image.memory( + response.bodyBytes, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print('❌ Error rendering image: $error'); + _failedImageUrls.add(imagePath); + return _buildDefaultCategoryIcon(); + }, + ); + } else { + print( + '❌ URL tidak menghasilkan gambar: Content-Type = $contentType'); + _failedImageUrls.add(imagePath); + return _buildDefaultCategoryIcon(); + } + } else { + print( + '❌ Failed to load image. Status code: ${response.statusCode}'); + _failedImageUrls.add(imagePath); + return _buildDefaultCategoryIcon(); + } + } else { + print('❌ No data received for image'); + _failedImageUrls.add(imagePath); + return _buildDefaultCategoryIcon(); + } + }, + ); + } else { + // For asset images + try { + // Check if it already has the full path or just the filename + final String assetPath = _getAssetPath(imagePath); + + print('🖼️ Loading asset from: $assetPath'); + + return Image.asset( + assetPath, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print('❌ Error loading asset image: $assetPath'); + print(' Error: $error'); + // Coba gunakan tailor_default.png sebagai fallback + if (assetPath != 'assets/images/tailor_default.png') { + print( + '🔄 Mencoba menggunakan tailor_default.png sebagai fallback'); + return Image.asset( + 'assets/images/tailor_default.png', + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print('❌ Fallback image juga gagal: $error'); + return _buildDefaultCategoryIcon(); + }, + ); + } + return _buildDefaultCategoryIcon(); + }, + ); + } catch (e) { + print('❌ Exception in _buildImage for asset: $e'); + return _buildDefaultCategoryIcon(); + } + } + } + + // Helper untuk menentukan path asset yang benar + String _getAssetPath(String path) { + // Daftar gambar default yang mungkin sudah terpasang di aplikasi + final knownAssets = { + 'tailor_default.png': 'assets/images/tailor_default.png', + 'avatar_default.png': + 'assets/images/tailor_default.png', // Fallback jika avatar_default tidak ada + 'default_profile.png': 'assets/images/tailor_default.png', + }; + + // Jika path adalah salah satu nama file default, gunakan path lengkap yang diketahui + if (knownAssets.containsKey(path)) { + return knownAssets[path]!; + } + + // Jika sudah memiliki path lengkap assets/ + if (path.startsWith('assets/')) { + return path; + } + + // Default pattern untuk assets + return 'assets/images/$path'; + } + + // Widget default untuk menampilkan ikon kategori + Widget _buildDefaultCategoryIcon() { + return Container( + color: Colors.grey[200], + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + categoryName.toLowerCase().contains('gaun') || + categoryName.toLowerCase().contains('dress') + ? Icons.checkroom + : categoryName.toLowerCase().contains('celana') || + categoryName.contains('pants') + ? Icons.accessibility_new + : categoryName.toLowerCase().contains('kemeja') || + categoryName.toLowerCase().contains('shirt') + ? Icons.add_box_outlined + : Icons.category, + color: Colors.grey[500], + size: 30, + ), + const SizedBox(height: 2), + Text( + categoryName.length > 3 + ? categoryName.substring(0, 3) + : categoryName, + style: TextStyle( + fontSize: 10, + color: Colors.grey[600], + ), + ), + ], + ), + ), + ); + } + + // Helper untuk memeriksa apakah URL valid + bool _isValidUrl(String url) { + try { + final uri = Uri.parse(url); + return uri.scheme.isNotEmpty && uri.host.isNotEmpty; + } catch (e) { + print('Invalid URL: $e'); + return false; + } + } + + // Helper untuk fetch image dengan HTTP request + Future _fetchImage(String url) async { + try { + // Tambahkan header untuk cache control + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'image/*', + 'Cache-Control': 'max-age=3600', // Cache satu jam + }, + ); + return response; + } catch (e) { + print('Error fetching image: $e'); + rethrow; + } + } + + /// Metode untuk menampilkan dialog debug saat ada masalah dengan gambar + static Future showImageDebugDialog( + BuildContext context, String url) async { + try { + // Periksa URL terlebih dahulu + final validationResult = await CategoryCard.debugImageUrl(url); + + // Tampilkan dialog dengan detail debug + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Image Debug Info'), + content: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text('URL: $url', + style: const TextStyle(fontWeight: FontWeight.bold)), + const Divider(), + const Text('Diagnostic results:'), + Text(validationResult.toString()), + const SizedBox(height: 10), + const Text('Troubleshooting steps:', + style: TextStyle(fontWeight: FontWeight.bold)), + const Text('1. Cek koneksi internet'), + const Text('2. Pastikan URL gambar benar'), + const Text('3. Periksa izin akses ke file'), + const Text('4. Periksa ukuran gambar (tidak terlalu besar)'), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Tutup'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + // Coba perbaiki URL gambar secara otomatis + ApiService.fixDesignPhotoUrl(url).then((fixedUrl) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(fixedUrl != url + ? 'URL berhasil diperbaiki: $fixedUrl' + : 'Tidak dapat memperbaiki URL'), + duration: const Duration(seconds: 3), + ), + ); + }); + }, + child: const Text('Coba Perbaiki'), + ), + ], + ), + ); + } catch (e) { + print('Error showing debug dialog: $e'); + } + } + + /// Metode untuk melakukan debug URL gambar + static Future> debugImageUrl(String url) async { + try { + print('\n====== DEBUG IMAGE URL ======'); + print('URL: $url'); + + // Validasi format URL + Uri? uri; + try { + uri = Uri.parse(url); + print( + 'URL valid dengan scheme: ${uri.scheme}, host: ${uri.host}, path: ${uri.path}'); + } catch (e) { + print('❌ URL tidak valid: $e'); + return {'success': false, 'error': 'URL tidak valid: $e', 'url': url}; + } + + // Coba ambil header untuk memeriksa status + try { + final headResponse = await http.head(uri); + print('HEAD response status: ${headResponse.statusCode}'); + print('HEAD response headers: ${headResponse.headers}'); + + if (headResponse.statusCode >= 400) { + return { + 'success': false, + 'error': + 'HEAD request gagal dengan status ${headResponse.statusCode}', + 'status': headResponse.statusCode, + 'url': url + }; + } + } catch (e) { + print('❌ Error melakukan HEAD request: $e'); + } + + // Coba ambil gambar untuk memeriksa content + try { + final getResponse = await http.get(uri); + print('GET response status: ${getResponse.statusCode}'); + print('GET content-type: ${getResponse.headers['content-type']}'); + print('GET content-length: ${getResponse.headers['content-length']}'); + + if (getResponse.statusCode == 200) { + final contentType = getResponse.headers['content-type']; + if (contentType != null && contentType.startsWith('image/')) { + print( + '✅ URL berisi gambar valid (${getResponse.bodyBytes.length} bytes)'); + return { + 'success': true, + 'message': 'URL berisi gambar valid', + 'contentType': contentType, + 'size': getResponse.bodyBytes.length, + 'url': url + }; + } else { + print( + '❌ URL tidak berisi konten gambar. Content-type: $contentType'); + return { + 'success': false, + 'error': 'URL tidak berisi konten gambar', + 'contentType': contentType, + 'url': url + }; + } + } else { + print('❌ GET request gagal dengan status: ${getResponse.statusCode}'); + return { + 'success': false, + 'error': + 'GET request gagal dengan status ${getResponse.statusCode}', + 'status': getResponse.statusCode, + 'url': url + }; + } + } catch (e) { + print('❌ Error melakukan GET request: $e'); + return {'success': false, 'error': 'Error GET request: $e', 'url': url}; + } + } catch (e) { + print('❌ Error debugging image URL: $e'); + return {'success': false, 'error': 'Error debugging: $e', 'url': url}; + } + } +} diff --git a/TA_android/lib/core/widgets/custom_button.dart b/TA_android/lib/core/widgets/custom_button.dart new file mode 100644 index 0000000..85e28b2 --- /dev/null +++ b/TA_android/lib/core/widgets/custom_button.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +class CustomButton extends StatelessWidget { + final String text; + final VoidCallback onPressed; + final double width; + final Color backgroundColor; + final Color textColor; + final double borderRadius; + final BorderSide? side; + final bool isLoading; + + const CustomButton({ + super.key, + required this.text, + required this.onPressed, + this.width = double.infinity, + this.backgroundColor = const Color(0xFF1A2552), + this.textColor = Colors.white, + this.borderRadius = 25, + this.side, + this.isLoading = false, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width, + child: ElevatedButton( + onPressed: isLoading ? null : onPressed, + style: ElevatedButton.styleFrom( + backgroundColor: backgroundColor, + foregroundColor: textColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(borderRadius), + side: side ?? BorderSide.none, + ), + padding: const EdgeInsets.symmetric(vertical: 12), + elevation: 0, + ), + child: isLoading + ? SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(textColor), + ), + ) + : Text( + text, + style: const TextStyle(fontSize: 16), + ), + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/custom_text_field.dart b/TA_android/lib/core/widgets/custom_text_field.dart new file mode 100644 index 0000000..db3c45b --- /dev/null +++ b/TA_android/lib/core/widgets/custom_text_field.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class CustomTextField extends StatelessWidget { + final TextEditingController controller; + final String labelText; + final bool obscureText; + final TextInputType keyboardType; + final int? maxLines; + final Widget? suffixIcon; + final String? Function(String?)? validator; + final String? hintText; + final int? maxLength; + final void Function(String)? onChanged; + final List? inputFormatters; + final TextCapitalization textCapitalization; + + const CustomTextField({ + super.key, + required this.controller, + required this.labelText, + this.obscureText = false, + this.keyboardType = TextInputType.text, + this.maxLines = 1, + this.suffixIcon, + this.validator, + this.hintText, + this.maxLength, + this.onChanged, + this.inputFormatters, + this.textCapitalization = TextCapitalization.none, + }); + + @override + Widget build(BuildContext context) { + return TextField( + controller: controller, + obscureText: obscureText, + keyboardType: keyboardType, + maxLines: maxLines, + maxLength: maxLength, + onChanged: onChanged, + inputFormatters: inputFormatters, + textCapitalization: textCapitalization, + decoration: InputDecoration( + labelText: labelText, + hintText: hintText, + labelStyle: TextStyle( + color: Colors.grey[600], + fontSize: 14, + ), + hintStyle: TextStyle( + color: Colors.grey[400], + fontSize: 14, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: Colors.grey[300]!), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + suffixIcon: suffixIcon, + counterText: '', // Sembunyikan counter text + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/dropdown_field.dart b/TA_android/lib/core/widgets/dropdown_field.dart new file mode 100644 index 0000000..0bbaf43 --- /dev/null +++ b/TA_android/lib/core/widgets/dropdown_field.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class DropdownField extends StatelessWidget { + final String value; + final VoidCallback onTap; + final double borderRadius; + final Color borderColor; + + const DropdownField({ + super.key, + required this.value, + required this.onTap, + this.borderRadius = 8, + this.borderColor = Colors.grey, + }); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + decoration: BoxDecoration( + border: Border.all(color: borderColor.withOpacity(0.3)), + borderRadius: BorderRadius.circular(borderRadius), + ), + child: Row( + children: [ + Expanded( + child: Text( + value, + style: TextStyle( + fontSize: 14, + color: value.startsWith('Pilih') ? Colors.grey : Colors.black, + ), + ), + ), + const Icon( + Icons.keyboard_arrow_down, + color: Colors.grey, + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/gallery_grid_widget.dart b/TA_android/lib/core/widgets/gallery_grid_widget.dart new file mode 100644 index 0000000..dad0cfa --- /dev/null +++ b/TA_android/lib/core/widgets/gallery_grid_widget.dart @@ -0,0 +1,237 @@ +import 'package:flutter/material.dart'; + +class GalleryGridWidget extends StatelessWidget { + final List? galleryItems; + final Function(String) onTapItem; + final Function(String) onLongPressItem; + final VoidCallback onAddItem; + final bool isLoading; + final bool isRefreshing; + final int crossAxisCount; + final double spacing; + + const GalleryGridWidget({ + super.key, + required this.galleryItems, + required this.onTapItem, + required this.onLongPressItem, + required this.onAddItem, + this.isLoading = false, + this.isRefreshing = false, + this.crossAxisCount = 3, + this.spacing = 8, + }); + + @override + Widget build(BuildContext context) { + if (isLoading) { + return SizedBox( + height: 200, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 16), + Text( + 'Memuat galeri...', + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 14, + ), + ), + ], + ), + ), + ); + } + + return Stack( + children: [ + GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + crossAxisSpacing: spacing, + mainAxisSpacing: spacing, + ), + itemCount: (galleryItems?.length ?? 0) + 1, // +1 untuk tombol tambah + itemBuilder: (context, index) { + // Jika ini adalah item terakhir (tombol tambah) + if (index == (galleryItems?.length ?? 0)) { + return GestureDetector( + onTap: isRefreshing ? null : onAddItem, + child: Container( + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Colors.grey.shade300, + width: 1, + ), + ), + child: Center( + child: Icon( + Icons.add_photo_alternate_outlined, + size: 32, + color: isRefreshing ? Colors.grey.shade300 : Colors.grey, + ), + ), + ), + ); + } + + // Tampilkan gambar galeri yang ada + final galleryItem = galleryItems![index]; + return GestureDetector( + onTap: isRefreshing ? null : () => onTapItem(galleryItem), + onLongPress: + isRefreshing ? null : () => onLongPressItem(galleryItem), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Colors.grey.shade300, + width: 1, + ), + ), + child: Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + galleryItem, + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + print('Error loading image: $galleryItem - $error'); + return Container( + color: Colors.grey.shade200, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.error_outline, + color: Colors.grey, + size: 32, + ), + const SizedBox(height: 4), + Text( + 'Gagal memuat', + style: TextStyle( + fontSize: 10, + color: Colors.grey.shade700, + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + }, + ), + ), + // Overlay for refreshing state + if (isRefreshing) + Positioned.fill( + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.3), + borderRadius: BorderRadius.circular(8), + ), + child: const Center( + child: SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: 2.0, + valueColor: + AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + ), + ), + ], + ), + ), + ); + }, + ), + + // Overlay refresh indicator + if (isRefreshing) + Positioned( + top: 0, + right: 0, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(8), + ), + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 12, + height: 12, + child: CircularProgressIndicator( + strokeWidth: 2.0, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + SizedBox(width: 4), + Text( + 'Memperbarui...', + style: TextStyle( + color: Colors.white, + fontSize: 10, + ), + ), + ], + ), + ), + ), + ], + ); + } +} + +// Versi yang lebih sederhana untuk penggunaan cepat +class SimpleGalleryGrid extends StatelessWidget { + final List? galleryItems; + final VoidCallback onAddTap; + final Function(String) onImageTap; + + const SimpleGalleryGrid({ + super.key, + required this.galleryItems, + required this.onAddTap, + required this.onImageTap, + }); + + @override + Widget build(BuildContext context) { + return GalleryGridWidget( + galleryItems: galleryItems, + onTapItem: onImageTap, + onLongPressItem: onImageTap, // Sama dengan onTap untuk versi sederhana + onAddItem: onAddTap, + ); + } +} diff --git a/TA_android/lib/core/widgets/image_upload_field.dart b/TA_android/lib/core/widgets/image_upload_field.dart new file mode 100644 index 0000000..4feb040 --- /dev/null +++ b/TA_android/lib/core/widgets/image_upload_field.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'dart:io'; + +class ImageUploadField extends StatelessWidget { + final String description; + final File? selectedImage; + final VoidCallback onTap; + + const ImageUploadField({ + super.key, + required this.description, + this.selectedImage, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Foto Referensi:', + style: TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + const SizedBox(height: 8), + InkWell( + onTap: onTap, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: selectedImage == null + ? Column( + children: [ + const Icon( + Icons.add_photo_alternate_outlined, + size: 40, + color: Color(0xFF1A2552), + ), + const SizedBox(height: 8), + Text( + description, + style: TextStyle( + fontSize: 14, + color: description == 'Belum ada foto' + ? Colors.grey + : Colors.black, + ), + ), + ], + ) + : Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + selectedImage!, + height: 150, + width: double.infinity, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + height: 150, + width: double.infinity, + color: Colors.grey.shade200, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.broken_image, + size: 40, + color: Colors.grey, + ), + const SizedBox(height: 8), + Text( + 'Gagal memuat gambar: $error', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + ], + ), + ); + }, + ), + ), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.check_circle, + color: Colors.green, + size: 16, + ), + const SizedBox(width: 4), + Text( + description, + style: const TextStyle( + fontSize: 14, + color: Colors.black, + ), + ), + ], + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/TA_android/lib/core/widgets/label_text.dart b/TA_android/lib/core/widgets/label_text.dart new file mode 100644 index 0000000..023991c --- /dev/null +++ b/TA_android/lib/core/widgets/label_text.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class LabelText extends StatelessWidget { + final String text; + final TextStyle? style; + final double bottomPadding; + + const LabelText({ + super.key, + required this.text, + this.style, + this.bottomPadding = 8.0, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(bottom: bottomPadding), + child: Text( + text, + style: style ?? + const TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/location_picker_dialog.dart b/TA_android/lib/core/widgets/location_picker_dialog.dart new file mode 100644 index 0000000..3eb2526 --- /dev/null +++ b/TA_android/lib/core/widgets/location_picker_dialog.dart @@ -0,0 +1,195 @@ +import 'package:flutter/material.dart'; +import 'location_picker_map.dart'; + +class LocationPickerDialog extends StatefulWidget { + final double? initialLatitude; + final double? initialLongitude; + final Function(double latitude, double longitude) onLocationSelected; + final bool isTailor; // Menandakan dialog untuk penjahit atau pelanggan + + const LocationPickerDialog({ + super.key, + this.initialLatitude, + this.initialLongitude, + required this.onLocationSelected, + this.isTailor = false, // Default untuk pelanggan + }); + + @override + State createState() => _LocationPickerDialogState(); +} + +class _LocationPickerDialogState extends State { + late double? selectedLatitude; + late double? selectedLongitude; + + @override + void initState() { + super.initState(); + selectedLatitude = widget.initialLatitude; + selectedLongitude = widget.initialLongitude; + } + + @override + Widget build(BuildContext context) { + return Dialog( + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.9, + maxHeight: MediaQuery.of(context).size.height * 0.8, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Header + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Expanded( + child: Text( + widget.isTailor + ? 'Pilih Lokasi Toko' + : 'Pilih Lokasi Anda', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ), + IconButton( + icon: const Icon(Icons.close), + onPressed: () => Navigator.of(context).pop(), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ], + ), + ), + const Divider(height: 1), + + // Informasi tentang pentingnya lokasi + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), + child: Container( + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(4), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 2.0), + child: Icon(Icons.info_outline, + color: Colors.blue.shade700, size: 16), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + widget.isTailor + ? 'Lokasi toko akan ditampilkan kepada pelanggan untuk memudahkan mereka menemukan jasa Anda' + : 'Lokasi Anda diperlukan untuk menemukan penjahit terdekat', + style: TextStyle( + fontSize: 12, + color: Colors.blue.shade800, + ), + ), + ), + ], + ), + ), + ), + + // Map + Expanded( + child: LocationPickerMap( + initialLatitude: widget.initialLatitude, + initialLongitude: widget.initialLongitude, + onLocationSelected: (lat, lng) { + setState(() { + selectedLatitude = lat; + selectedLongitude = lng; + }); + }, + ), + ), + + // Actions + // Info lokasi + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + child: selectedLatitude != null + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Koordinat Terpilih:', + style: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + Text( + 'Lat: ${selectedLatitude!.toStringAsFixed(6)}\nLng: ${selectedLongitude!.toStringAsFixed(6)}', + style: const TextStyle( + fontSize: 14, + color: Color(0xFF1A2552), + ), + ), + ], + ) + : const Text( + 'Belum ada lokasi terpilih', + style: TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + ), + + // Action buttons + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text( + 'Batal', + style: TextStyle(color: Colors.grey), + ), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: selectedLatitude != null + ? () { + widget.onLocationSelected( + selectedLatitude!, + selectedLongitude!, + ); + Navigator.of(context).pop(); + } + : null, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 8), + ), + child: const Text('Simpan Lokasi'), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/location_picker_map.dart b/TA_android/lib/core/widgets/location_picker_map.dart new file mode 100644 index 0000000..c32edd7 --- /dev/null +++ b/TA_android/lib/core/widgets/location_picker_map.dart @@ -0,0 +1,229 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:geolocator/geolocator.dart'; + +class LocationPickerMap extends StatefulWidget { + final double? initialLatitude; + final double? initialLongitude; + final Function(double latitude, double longitude) onLocationSelected; + + const LocationPickerMap({ + super.key, + this.initialLatitude, + this.initialLongitude, + required this.onLocationSelected, + }); + + @override + State createState() => _LocationPickerMapState(); +} + +class _LocationPickerMapState extends State { + late MapController _mapController; + LatLng _selectedLocation = const LatLng(-6.2088, 106.8456); // Default Jakarta + bool _isLoading = false; + bool _hasError = false; + String _errorMessage = ''; + + @override + void initState() { + super.initState(); + _mapController = MapController(); + + // Gunakan initial location jika ada + if (widget.initialLatitude != null && widget.initialLongitude != null) { + _selectedLocation = + LatLng(widget.initialLatitude!, widget.initialLongitude!); + } + + // Jika tidak ada lokasi awal, coba dapatkan lokasi saat ini + if (widget.initialLatitude == null && widget.initialLongitude == null) { + _getCurrentLocation(); + } + } + + Future _getCurrentLocation() async { + setState(() { + _isLoading = true; + _hasError = false; + _errorMessage = ''; + }); + + try { + // Cek izin lokasi + LocationPermission permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + // Izin ditolak, gunakan lokasi default + setState(() { + _hasError = true; + _errorMessage = 'Izin lokasi ditolak. Menggunakan lokasi default.'; + _isLoading = false; + }); + _showSnackBar('Izin lokasi ditolak. Menggunakan lokasi default.'); + return; + } + } + + if (permission == LocationPermission.deniedForever) { + // Izin ditolak permanen, gunakan lokasi default + setState(() { + _hasError = true; + _errorMessage = 'Izin lokasi ditolak permanen. Silakan ubah di pengaturan perangkat.'; + _isLoading = false; + }); + _showSnackBar( + 'Izin lokasi ditolak permanen. Silakan ubah di pengaturan perangkat.'); + return; + } + + // Gunakan akurasi rendah untuk menghindari kebutuhan ACCESS_FINE_LOCATION + Position position = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.low, + ); + + setState(() { + _selectedLocation = LatLng(position.latitude, position.longitude); + _hasError = false; + }); + + // Gerakkan peta ke lokasi saat ini + _mapController.move(_selectedLocation, 15); + + // Set lokasi yang dipilih + widget.onLocationSelected( + _selectedLocation.latitude, _selectedLocation.longitude); + } catch (e) { + setState(() { + _hasError = true; + _errorMessage = 'Gagal mendapatkan lokasi saat ini: $e'; + }); + _showSnackBar('Gagal mendapatkan lokasi saat ini: $e'); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + void _showSnackBar(String message) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(message), + duration: const Duration(seconds: 3), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + if (_isLoading) + const LinearProgressIndicator() + else if (_hasError) + Container( + padding: const EdgeInsets.all(8), + color: Colors.red.shade50, + width: double.infinity, + child: Text( + _errorMessage, + style: TextStyle(color: Colors.red.shade700, fontSize: 12), + textAlign: TextAlign.center, + ), + ) + else + const SizedBox(height: 4), + Expanded( + child: Stack( + children: [ + // Peta + FlutterMap( + mapController: _mapController, + options: MapOptions( + initialCenter: _selectedLocation, + initialZoom: 15.0, + minZoom: 5.0, + maxZoom: 18.0, + onTap: (tapPosition, latLng) { + setState(() { + _selectedLocation = latLng; + }); + widget.onLocationSelected( + latLng.latitude, latLng.longitude); + }, + ), + children: [ + // Layer peta + TileLayer( + urlTemplate: + 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + userAgentPackageName: 'com.example.tailorhub', + subdomains: const ['a', 'b', 'c'], + ), + // Marker + MarkerLayer( + markers: [ + Marker( + width: 40.0, + height: 40.0, + point: _selectedLocation, + child: const Icon( + Icons.location_pin, + color: Color(0xFF1A2552), + size: 40, + ), + ), + ], + ), + ], + ), + // Tombol lokasi saat ini + Positioned( + right: 16, + bottom: 16, + child: FloatingActionButton( + heroTag: 'GetLocationBtn', + mini: true, + backgroundColor: const Color(0xFF1A2552), + onPressed: _getCurrentLocation, + child: const Icon(Icons.my_location, color: Colors.white), + ), + ), + // Info koordinat + Positioned( + left: 0, + right: 0, + bottom: 0, + child: Container( + color: Colors.white.withOpacity(0.8), + padding: + const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Text( + 'Latitude: ${_selectedLocation.latitude.toStringAsFixed(6)}\nLongitude: ${_selectedLocation.longitude.toStringAsFixed(6)}', + style: const TextStyle( + fontSize: 12, fontWeight: FontWeight.bold), + ), + ), + ), + ], + ), + ), + // Instruksi + Container( + padding: const EdgeInsets.all(8), + color: Colors.grey[200], + width: double.infinity, + child: const Text( + 'Ketuk pada peta untuk memilih lokasi atau gunakan tombol lokasi saat ini', + style: TextStyle(fontSize: 12, color: Colors.black54), + textAlign: TextAlign.center, + ), + ), + ], + ); + } +} diff --git a/TA_android/lib/core/widgets/multiline_text_field.dart b/TA_android/lib/core/widgets/multiline_text_field.dart new file mode 100644 index 0000000..a778624 --- /dev/null +++ b/TA_android/lib/core/widgets/multiline_text_field.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class MultilineTextField extends StatelessWidget { + final TextEditingController? controller; + final String hintText; + final int maxLines; + final Function(String)? onChanged; + + const MultilineTextField({ + super.key, + this.controller, + required this.hintText, + this.maxLines = 4, + this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: TextField( + controller: controller, + maxLines: maxLines, + onChanged: onChanged, + decoration: InputDecoration( + hintText: hintText, + hintStyle: const TextStyle(fontSize: 12, color: Colors.grey), + border: InputBorder.none, + ), + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/password_field.dart b/TA_android/lib/core/widgets/password_field.dart new file mode 100644 index 0000000..3435cff --- /dev/null +++ b/TA_android/lib/core/widgets/password_field.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +class PasswordField extends StatefulWidget { + final TextEditingController controller; + final String labelText; + final String? Function(String?)? validator; + final String? hintText; + + const PasswordField({ + super.key, + required this.controller, + required this.labelText, + this.validator, + this.hintText, + }); + + @override + State createState() => _PasswordFieldState(); +} + +class _PasswordFieldState extends State { + bool _obscurePassword = true; + + @override + Widget build(BuildContext context) { + return TextField( + controller: widget.controller, + obscureText: _obscurePassword, + decoration: InputDecoration( + labelText: widget.labelText, + hintText: widget.hintText, + labelStyle: TextStyle( + color: Colors.grey[600], + fontSize: 14, + ), + hintStyle: TextStyle( + color: Colors.grey[400], + fontSize: 14, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide(color: Colors.grey[300]!), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, + ), + suffixIcon: IconButton( + icon: Icon( + _obscurePassword ? Icons.visibility_off : Icons.visibility, + color: Colors.grey, + ), + onPressed: () { + setState(() { + _obscurePassword = !_obscurePassword; + }); + }, + ), + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/success_dialog.dart b/TA_android/lib/core/widgets/success_dialog.dart new file mode 100644 index 0000000..11942cf --- /dev/null +++ b/TA_android/lib/core/widgets/success_dialog.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +class SuccessDialog extends StatelessWidget { + final String title; + final String message; + final String buttonText; + final VoidCallback onButtonPressed; + + const SuccessDialog({ + super.key, + required this.title, + required this.message, + required this.buttonText, + required this.onButtonPressed, + }); + + @override + Widget build(BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 12), + Text( + message, + style: const TextStyle( + fontSize: 14, + color: Colors.grey, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: onButtonPressed, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + minimumSize: const Size(200, 45), + ), + child: Text( + buttonText, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/core/widgets/tailor_card.dart b/TA_android/lib/core/widgets/tailor_card.dart new file mode 100644 index 0000000..51a911e --- /dev/null +++ b/TA_android/lib/core/widgets/tailor_card.dart @@ -0,0 +1,183 @@ +import 'package:flutter/material.dart'; + +class TailorCard extends StatelessWidget { + final String name; + final String? subtitle; + final String imagePath; + final VoidCallback? onTap; + final double? rating; + final int? reviewCount; + + const TailorCard({ + super.key, + required this.name, + this.subtitle, + required this.imagePath, + this.onTap, + this.rating, + this.reviewCount, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Container( + width: 120, + margin: const EdgeInsets.only(right: 10), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Container dengan gambar penjahit + Stack( + children: [ + Container( + width: 120, + height: 100, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 2, + offset: const Offset(0, 1), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: imagePath.startsWith('http') + ? Image.network( + imagePath, + width: 120, + height: 100, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + color: Colors.grey[200], + child: const Icon(Icons.store, + size: 40, color: Colors.grey), + ); + }, + ) + : Image.asset( + imagePath, + width: 120, + height: 100, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + color: Colors.grey[200], + child: const Icon(Icons.store, + size: 40, color: Colors.grey), + ); + }, + ), + ), + ), + + // Badge rating di pojok kanan atas jika ada rating + if (rating != null) + Positioned( + top: 8, + right: 8, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.6), + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + Icons.star, + color: Colors.amber, + size: 14, + ), + const SizedBox(width: 2), + Text( + rating!.toStringAsFixed(1), + style: const TextStyle( + color: Colors.white, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ), + ], + ), + const SizedBox(height: 4), + + // Nama penjahit (rata kiri dan bold) + Text( + name, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, + color: Colors.black87, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + + // Rating bar di bawah nama + if (rating != null) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + _buildRatingStars(rating!), + if (reviewCount != null) ...[ + const SizedBox(width: 2), + Text( + '($reviewCount)', + style: TextStyle( + fontSize: 9, + color: Colors.grey.shade600, + ), + ), + ], + ], + ), + + // Subtitle/alamat (rata kiri dan abu-abu) + if (subtitle != null) + Text( + subtitle!, + style: TextStyle( + fontSize: 10, + color: Colors.grey.shade600, + height: 1.2, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ); + } + + // Widget untuk menampilkan rating stars + Widget _buildRatingStars(double rating) { + int fullStars = rating.floor(); + bool hasHalfStar = (rating - fullStars) >= 0.5; + + return Row( + mainAxisSize: MainAxisSize.min, + children: List.generate(5, (index) { + if (index < fullStars) { + return const Icon(Icons.star, size: 10, color: Colors.amber); + } else if (index == fullStars && hasHalfStar) { + return const Icon(Icons.star_half, size: 10, color: Colors.amber); + } else { + return Icon(Icons.star_border, size: 10, color: Colors.grey.shade400); + } + }), + ); + } +} diff --git a/TA_android/lib/features/wallet/widgets/add_bank_account_form.dart b/TA_android/lib/features/wallet/widgets/add_bank_account_form.dart new file mode 100644 index 0000000..ca3736b --- /dev/null +++ b/TA_android/lib/features/wallet/widgets/add_bank_account_form.dart @@ -0,0 +1,204 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../../core/controllers/wallet_wd_controller.dart'; +import '../../../core/theme/colors.dart'; + +class AddBankAccountForm extends StatefulWidget { + const AddBankAccountForm({super.key}); + + @override + State createState() => _AddBankAccountFormState(); +} + +class _AddBankAccountFormState extends State { + final _formKey = GlobalKey(); + final _accountNumberController = TextEditingController(); + final _accountHolderController = TextEditingController(); + String _selectedBank = 'BCA'; + bool _isSubmitting = false; + + final List _bankList = [ + 'BCA', + 'Mandiri', + 'BNI', + 'BRI', + 'CIMB Niaga', + 'Permata', + ]; + + @override + void dispose() { + _accountNumberController.dispose(); + _accountHolderController.dispose(); + super.dispose(); + } + + String? _validateAccountNumber(String? value) { + if (value == null || value.isEmpty) { + return 'Nomor rekening tidak boleh kosong'; + } + if (!RegExp(r'^[0-9]{10,16}$').hasMatch(value)) { + return 'Nomor rekening harus 10-16 digit angka'; + } + return null; + } + + String? _validateAccountHolder(String? value) { + if (value == null || value.isEmpty) { + return 'Nama pemilik rekening tidak boleh kosong'; + } + if (value.length < 3) { + return 'Nama pemilik rekening minimal 3 karakter'; + } + return null; + } + + Future _submitForm() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _isSubmitting = true); + + try { + final result = await context.read().registerBankAccount( + bankName: _selectedBank, + accountNumber: _accountNumberController.text, + accountHolderName: _accountHolderController.text, + ); + + if (!mounted) return; + + if (result['success']) { + _showSuccessDialog(); + } else { + _showErrorDialog(result['message']); + } + } catch (e) { + _showErrorDialog('Terjadi kesalahan: $e'); + } finally { + if (mounted) { + setState(() => _isSubmitting = false); + } + } + } + + void _showSuccessDialog() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Berhasil'), + content: const Text('Rekening bank berhasil didaftarkan dan sedang menunggu verifikasi.'), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); // Tutup dialog + Navigator.pop(context); // Kembali ke halaman sebelumnya + }, + child: const Text('OK'), + ), + ], + ), + ); + } + + void _showErrorDialog(String message) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Gagal'), + content: Text(message), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('OK'), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'Tambah Rekening Bank', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: AppColors.primary, + ), + ), + const SizedBox(height: 24), + DropdownButtonFormField( + value: _selectedBank, + decoration: const InputDecoration( + labelText: 'Bank', + border: OutlineInputBorder(), + prefixIcon: Icon(Icons.account_balance), + ), + items: _bankList.map((bank) { + return DropdownMenuItem( + value: bank, + child: Text(bank), + ); + }).toList(), + onChanged: (value) { + if (value != null) { + setState(() => _selectedBank = value); + } + }, + ), + const SizedBox(height: 16), + TextFormField( + controller: _accountNumberController, + decoration: const InputDecoration( + labelText: 'Nomor Rekening', + border: OutlineInputBorder(), + prefixIcon: Icon(Icons.credit_card), + ), + keyboardType: TextInputType.number, + validator: _validateAccountNumber, + ), + const SizedBox(height: 16), + TextFormField( + controller: _accountHolderController, + decoration: const InputDecoration( + labelText: 'Nama Pemilik Rekening', + border: OutlineInputBorder(), + prefixIcon: Icon(Icons.person), + ), + textCapitalization: TextCapitalization.words, + validator: _validateAccountHolder, + ), + const SizedBox(height: 24), + ElevatedButton( + onPressed: _isSubmitting ? null : _submitForm, + style: ElevatedButton.styleFrom( + backgroundColor: AppColors.primary, + padding: const EdgeInsets.symmetric(vertical: 16), + ), + child: _isSubmitting + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + : const Text( + 'Daftarkan Rekening', + style: TextStyle(fontSize: 16), + ), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/TA_android/lib/main.dart b/TA_android/lib/main.dart new file mode 100644 index 0000000..f79431b --- /dev/null +++ b/TA_android/lib/main.dart @@ -0,0 +1,141 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'core/routes/routes.dart' as app_routes; +import 'package:google_fonts/google_fonts.dart'; +import 'core/providers/user_provider.dart'; +import 'core/services/api_service.dart'; +import 'core/utils/logger.dart'; +import 'core/controllers/booking_controller.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'core/controllers/midtrans_controller.dart'; +import 'core/controllers/wallet_wd_controller.dart'; +import 'pages/tailor/wallet/withdrawal_page.dart'; +import 'pages/tailor/wallet/wallet_history_page.dart'; +import 'pages/tailor/wallet/add_bank_account_page.dart'; +import 'package:intl/date_symbol_data_local.dart'; +// ignore_for_file: avoid_print + +void main() async { + // Tangkap semua error yang tidak tertangani + runZonedGuarded(() async { + // Pastikan Flutter diinisialisasi terlebih dahulu + WidgetsFlutterBinding.ensureInitialized(); + + try { + // Load konfigurasi dari .env file + await dotenv.load(fileName: ".env"); + print("✅ Berhasil memuat .env dari root"); + } catch (e) { + print("⚠️ Gagal memuat .env: $e"); + + // Set nilai default untuk development lokal + dotenv.env['API_BASE_URL'] = 'https://api-tailorhub.stuffly.my.id/api'; // Android emulator -> localhost + dotenv.env['API_IMAGE_BASE_URL'] = 'https://api-tailorhub.stuffly.my.id/api'; + + + print("🔧 Menggunakan URL lokal untuk development"); + } + + // Inisialisasi locale formatting untuk date/time + await initializeDateFormatting('id', null); + + // Cetak nilai variabel lingkungan untuk debugging + print("👉 API_BASE_URL: ${dotenv.env['API_BASE_URL']}"); + print("👉 API_IMAGE_BASE_URL: ${dotenv.env['API_IMAGE_BASE_URL']}"); + + // Aktifkan verbose logging di mode debug + AppLogger.enableVerboseLogging(true); + AppLogger.info('Starting TailorHub Application'); + + // Inisialisasi API Service + await ApiService.init(); + + // Tangkap Flutter error + FlutterError.onError = (FlutterErrorDetails details) { + FlutterError.presentError(details); + AppLogger.error( + 'Flutter error', + error: details.exception, + stackTrace: details.stack, + ); + }; + + // Selalu mulai dari splash screen untuk UX yang lebih baik + runApp( + MultiProvider( + providers: [ + ChangeNotifierProvider(create: (_) => UserProvider()), + ChangeNotifierProvider(create: (_) => WalletWDController()), + ChangeNotifierProvider(create: (_) => BookingController()), + ChangeNotifierProvider(create: (_) => MidtransController()), + ], + child: const MyApp(initialRoute: AppRoutes.splash), + ), + ); + }, (error, stackTrace) { + // Tangkap error pada Zone + AppLogger.error( + 'Uncaught error in app', + error: error, + stackTrace: stackTrace, + ); + }); +} + +class AppRoutes { + static const String splash = '/'; + static const String login = '/login'; + static const String register = '/register'; + static const String home = '/home'; + static const String withdrawal = '/withdrawal'; + static const String walletHistory = '/wallet-history'; + static const String addBankAccount = '/add-bank-account'; + // ... existing routes ... +} + +class MyApp extends StatelessWidget { + final String initialRoute; + + const MyApp({ + super.key, + required this.initialRoute, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'TailorHub', + theme: ThemeData( + primaryColor: const Color(0xFF1A2552), + textTheme: GoogleFonts.interTextTheme(Theme.of(context).textTheme), + colorScheme: ColorScheme.fromSeed( + seedColor: const Color(0xFF1A2552), + ), + ), + debugShowCheckedModeBanner: false, + initialRoute: initialRoute, + routes: app_routes.AppRoutes.getRoutes(), + onGenerateRoute: (settings) { + // Handle wallet related routes + switch (settings.name) { + case AppRoutes.withdrawal: + return MaterialPageRoute( + builder: (context) => const WithdrawalPage(), + ); + case AppRoutes.walletHistory: + return MaterialPageRoute( + builder: (context) => const WalletHistoryPage(), + ); + case AppRoutes.addBankAccount: + return MaterialPageRoute( + builder: (context) => const AddBankAccountPage(), + ); + default: + // Use the default route generator from routes.dart + return app_routes.AppRoutes.onGenerateRoute(settings); + } + }, + ); + } +} diff --git a/TA_android/lib/pages/auth/forgot_password_customer_page.dart b/TA_android/lib/pages/auth/forgot_password_customer_page.dart new file mode 100644 index 0000000..c9cfccb --- /dev/null +++ b/TA_android/lib/pages/auth/forgot_password_customer_page.dart @@ -0,0 +1,485 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import '../../core/widgets/custom_text_field.dart'; +import '../../core/widgets/custom_button.dart'; +import '../../core/widgets/password_field.dart'; +import '../../core/controllers/auth_controller.dart'; +import '../../core/services/forgot_passowrd_service.dart'; +// ignore_for_file: avoid_print + +class ForgotPasswordCustomerPage extends StatefulWidget { + const ForgotPasswordCustomerPage({super.key}); + + @override + State createState() => + _ForgotPasswordCustomerPageState(); +} + +class _ForgotPasswordCustomerPageState + extends State { + final AuthController _authController = AuthController(); + final ForgotPasswordService _forgotPasswordService = ForgotPasswordService(); + final TextEditingController _pinController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _passwordConfirmationController = + TextEditingController(); + final _formKey = GlobalKey(); + + bool _isEmailSent = false; + String _errorMessage = ''; + bool _isLoading = false; + bool _isResetting = false; + + @override + void dispose() { + _authController.dispose(); + _pinController.dispose(); + _passwordController.dispose(); + _passwordConfirmationController.dispose(); + super.dispose(); + } + + Future _resetPassword() async { + print('DEBUG: Memulai proses forgot password customer'); + print('DEBUG: Email yang diinput: ${_authController.emailController.text}'); + + if (!_authController.validateForgotPassword(context)) { + print('DEBUG: Validasi email gagal'); + setState(() { + _errorMessage = 'Email tidak boleh kosong'; + _isEmailSent = false; + }); + return; + } + + setState(() { + _isLoading = true; + _errorMessage = ''; + }); + + try { + print('DEBUG: Mengirim request forgot password ke server'); + final result = await _forgotPasswordService.forgotPasswordCustomer( + _authController.emailController.text, + ); + + print('DEBUG: Response dari server: $result'); + + setState(() { + _isLoading = false; + _isEmailSent = result['success']; + if (!result['success']) { + _errorMessage = result['message']; + print('DEBUG: Gagal mengirim email: ${result['message']}'); + } else { + print('DEBUG: Email berhasil dikirim'); + } + }); + + if (!mounted) return; + + // Tampilkan snackbar dengan pesan dari server + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: result['success'] ? Colors.green : Colors.red, + ), + ); + } catch (e, stackTrace) { + print('ERROR: Terjadi kesalahan saat forgot password:'); + print('ERROR: $e'); + print('ERROR: Stack trace:'); + print(stackTrace); + + setState(() { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + }); + } + } + + Future _submitResetPassword() async { + print('DEBUG: Memulai proses reset password customer'); + + if (!_formKey.currentState!.validate()) { + print('DEBUG: Validasi form gagal'); + return; + } + + setState(() { + _isResetting = true; + _errorMessage = ''; + }); + + try { + print('DEBUG: Mengirim request reset password ke server'); + final result = await _forgotPasswordService.resetPasswordCustomer( + email: _authController.emailController.text, + password: _passwordController.text, + passwordConfirmation: _passwordConfirmationController.text, + pin: _pinController.text, + ); + + print('DEBUG: Response dari server: $result'); + + setState(() => _isResetting = false); + + if (!mounted) return; + + if (result['success']) { + print('DEBUG: Reset password berhasil'); + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.check_circle, color: Colors.green), + SizedBox(width: 8), + Text('Berhasil'), + ], + ), + content: const Text( + 'Password berhasil direset. Silakan login dengan password baru.'), + actions: [ + TextButton( + onPressed: () { + print('DEBUG: Menutup dialog dan kembali ke halaman login'); + Navigator.of(context).pop(); // Tutup dialog + Navigator.of(context).pop(); // Kembali ke halaman login + }, + child: const Text('OK'), + ), + ], + ), + ); + } else { + print('DEBUG: Reset password gagal'); + + // Ambil pesan error dari response + String errorMessage = 'Terjadi kesalahan saat mereset password'; + + if (result['data'] != null && result['data'] is Map) { + // Cek pesan error di data + final Map data = + result['data'] as Map; + if (data.containsKey('email')) { + errorMessage = data['email'].toString(); + } + } + + // Jika ada errors object, gunakan itu + if (result['errors'] != null && result['errors'] is Map) { + final Map errors = + result['errors'] as Map; + if (errors.isNotEmpty) { + errorMessage = errors.values.first.toString(); + } + } + + print('DEBUG: Error message yang akan ditampilkan: $errorMessage'); + + // Update state dengan pesan error + setState(() { + _errorMessage = errorMessage; + }); + + // Tampilkan snackbar dengan pesan error + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(errorMessage), + backgroundColor: Colors.red, + duration: const Duration(seconds: 5), + action: SnackBarAction( + label: 'OK', + textColor: Colors.white, + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + }, + ), + ), + ); + + // Tampilkan dialog error + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.error_outline, color: Colors.red), + SizedBox(width: 8), + Text('Gagal Reset Password'), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(errorMessage), + const SizedBox(height: 8), + const Text( + 'Pastikan PIN yang Anda masukkan benar dan belum kadaluarsa.', + style: TextStyle(fontSize: 12, color: Colors.grey), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + // Reset form jika diperlukan + _pinController.clear(); + _passwordController.clear(); + _passwordConfirmationController.clear(); + }, + child: const Text('OK'), + ), + ], + ), + ); + } + } catch (e, stackTrace) { + print('ERROR: Terjadi kesalahan saat reset password:'); + print('ERROR: $e'); + print('ERROR: Stack trace:'); + print(stackTrace); + + setState(() { + _isResetting = false; + _errorMessage = 'Terjadi kesalahan sistem. Silakan coba lagi nanti.'; + }); + + if (!mounted) return; + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + const Text('Terjadi kesalahan sistem. Silakan coba lagi nanti.'), + backgroundColor: Colors.red, + duration: const Duration(seconds: 5), + action: SnackBarAction( + label: 'Detail', + textColor: Colors.white, + onPressed: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.error_outline, color: Colors.red), + SizedBox(width: 8), + Text('Detail Error'), + ], + ), + content: SingleChildScrollView( + child: Text( + 'Error: $e\n\nStack Trace:\n$stackTrace', + style: const TextStyle(fontSize: 12), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Tutup'), + ), + ], + ), + ); + }, + ), + ), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + title: const Text( + 'Lupa Password?', + style: TextStyle( + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + centerTitle: true, + ), + body: Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Text( + 'Lupa Password?', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 10), + Text( + _isEmailSent + ? 'Masukkan PIN 6 digit yang telah dikirim ke email Anda' + : 'Masukkan Email yang sudah terdaftar sebagai Customer', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + const SizedBox(height: 30), + + if (!_isEmailSent) ...[ + // Form untuk mengirim email + CustomTextField( + controller: _authController.emailController, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Email tidak boleh kosong'; + } + if (!value.contains('@')) { + return 'Email tidak valid'; + } + return null; + }, + ), + const SizedBox(height: 20), + CustomButton( + text: 'Kirim', + onPressed: _resetPassword, + isLoading: _isLoading, + ), + ] else ...[ + // Form untuk reset password + CustomTextField( + controller: _pinController, + labelText: 'PIN', + hintText: 'Masukkan 6 digit PIN dari email', + maxLength: 6, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + validator: (value) { + if (value == null || value.isEmpty) { + return 'PIN tidak boleh kosong'; + } + if (value.length != 6) { + return 'PIN harus 6 digit'; + } + if (!RegExp(r'^\d+$').hasMatch(value)) { + return 'PIN hanya boleh berisi angka'; + } + return null; + }, + ), + const SizedBox(height: 15), + PasswordField( + controller: _passwordController, + labelText: 'Password Baru', + hintText: 'Minimal 8 karakter', + validator: (value) { + if (value == null || value.isEmpty) { + return 'Password tidak boleh kosong'; + } + if (value.length < 8) { + return 'Password minimal 8 karakter'; + } + return null; + }, + ), + const SizedBox(height: 15), + PasswordField( + controller: _passwordConfirmationController, + labelText: 'Konfirmasi Password', + hintText: 'Masukkan ulang password baru', + validator: (value) { + if (value == null || value.isEmpty) { + return 'Konfirmasi password tidak boleh kosong'; + } + if (value != _passwordController.text) { + return 'Konfirmasi password tidak cocok'; + } + return null; + }, + ), + const SizedBox(height: 20), + CustomButton( + text: 'Reset Password', + onPressed: _submitResetPassword, + isLoading: _isResetting, + ), + ], + + const SizedBox(height: 20), + + // Error message + if (_errorMessage.isNotEmpty) + _buildMessageContainer( + icon: Icons.error, + iconColor: Colors.red[400]!, + backgroundColor: Colors.red[100]!, + textColor: Colors.red[900]!, + message: _errorMessage, + ), + ], + ), + ), + ), + ), + ), + ); + } + + Widget _buildMessageContainer({ + required IconData icon, + required Color iconColor, + required Color backgroundColor, + required Color textColor, + required String message, + }) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Icon( + icon, + color: iconColor, + size: 20, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + message, + style: TextStyle( + fontSize: 12, + color: textColor, + ), + ), + ), + ], + ), + ); + } +} diff --git a/TA_android/lib/pages/auth/forgot_password_page.dart b/TA_android/lib/pages/auth/forgot_password_page.dart new file mode 100644 index 0000000..647d3c0 --- /dev/null +++ b/TA_android/lib/pages/auth/forgot_password_page.dart @@ -0,0 +1,162 @@ +import 'package:flutter/material.dart'; +import '../../core/widgets/custom_text_field.dart'; +import '../../core/widgets/custom_button.dart'; +import '../../core/controllers/auth_controller.dart'; + +class ForgotPasswordPage extends StatefulWidget { + const ForgotPasswordPage({super.key}); + + @override + State createState() => _ForgotPasswordPageState(); +} + +class _ForgotPasswordPageState extends State { + final AuthController _authController = AuthController(); + bool _isEmailSent = false; + String _errorMessage = ''; + + @override + void dispose() { + _authController.dispose(); + super.dispose(); + } + + void _resetPassword() { + if (!_authController.validateForgotPassword(context)) { + setState(() { + _errorMessage = 'Email tidak boleh kosong'; + _isEmailSent = false; + }); + return; + } + + // Simulasi kirim email reset password + setState(() { + _isEmailSent = true; + _errorMessage = ''; + }); + + // Di implementasi nyata, di sini akan memanggil API untuk reset password + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + title: const Text( + 'Lupa Password?', + style: TextStyle( + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + centerTitle: true, + ), + body: Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Text( + 'Lupa Password?', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 10), + const Text( + 'Masukkan Email yang sudah terdaftar', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + const SizedBox(height: 30), + // Email field + CustomTextField( + controller: _authController.emailController, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 20), + // Kirim button + CustomButton( + text: 'Kirim', + onPressed: _resetPassword, + ), + const SizedBox(height: 20), + // Success or Error message + if (_isEmailSent) + _buildMessageContainer( + icon: Icons.check_circle, + iconColor: Colors.pink[400]!, + backgroundColor: Colors.pink[100]!, + textColor: Colors.pink[900]!, + message: + 'Email reset password akan dikirim jika email terdaftar', + ), + if (_errorMessage.isNotEmpty) + _buildMessageContainer( + icon: Icons.error, + iconColor: Colors.red[400]!, + backgroundColor: Colors.red[100]!, + textColor: Colors.red[900]!, + message: _errorMessage, + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildMessageContainer({ + required IconData icon, + required Color iconColor, + required Color backgroundColor, + required Color textColor, + required String message, + }) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Icon( + icon, + color: iconColor, + size: 20, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + message, + style: TextStyle( + fontSize: 12, + color: textColor, + ), + ), + ), + ], + ), + ); + } +} diff --git a/TA_android/lib/pages/auth/forgot_password_tailor_page.dart b/TA_android/lib/pages/auth/forgot_password_tailor_page.dart new file mode 100644 index 0000000..633024f --- /dev/null +++ b/TA_android/lib/pages/auth/forgot_password_tailor_page.dart @@ -0,0 +1,365 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import '../../core/widgets/custom_text_field.dart'; +import '../../core/widgets/custom_button.dart'; +import '../../core/widgets/password_field.dart'; +import '../../core/controllers/auth_controller.dart'; +import '../../core/services/forgot_passowrd_service.dart'; +// ignore_for_file: avoid_print + +class ForgotPasswordTailorPage extends StatefulWidget { + const ForgotPasswordTailorPage({super.key}); + + @override + State createState() => + _ForgotPasswordTailorPageState(); +} + +class _ForgotPasswordTailorPageState extends State { + final _formKey = GlobalKey(); + final AuthController _authController = AuthController(); + final ForgotPasswordService _forgotPasswordService = ForgotPasswordService(); + final TextEditingController _pinController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _passwordConfirmationController = + TextEditingController(); + + bool _isEmailSent = false; + String _errorMessage = ''; + bool _isLoading = false; + bool _isResetting = false; + + @override + void dispose() { + _authController.dispose(); + _pinController.dispose(); + _passwordController.dispose(); + _passwordConfirmationController.dispose(); + super.dispose(); + } + + Future _resetPassword() async { + print('DEBUG: Memulai proses forgot password tailor'); + print('DEBUG: Email yang diinput: ${_authController.emailController.text}'); + + if (!_authController.validateForgotPassword(context)) { + print('DEBUG: Validasi email gagal'); + setState(() { + _errorMessage = 'Email tidak boleh kosong'; + _isEmailSent = false; + }); + return; + } + + setState(() { + _isLoading = true; + _errorMessage = ''; + }); + + try { + print('DEBUG: Mengirim request forgot password ke server'); + final result = await _forgotPasswordService.forgotPasswordTailor( + _authController.emailController.text, + ); + + print('DEBUG: Response dari server: $result'); + + setState(() { + _isLoading = false; + _isEmailSent = result['success']; + if (!result['success']) { + _errorMessage = result['message']; + print('DEBUG: Gagal mengirim email: ${result['message']}'); + } else { + print('DEBUG: Email berhasil dikirim'); + } + }); + + if (!mounted) return; + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: result['success'] ? Colors.green : Colors.red, + ), + ); + } catch (e, stackTrace) { + print('ERROR: Terjadi kesalahan saat forgot password:'); + print('ERROR: $e'); + print('ERROR: Stack trace:'); + print(stackTrace); + + setState(() { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + }); + } + } + + Future _submitResetPassword() async { + print('DEBUG: Memulai proses reset password tailor'); + + if (!_formKey.currentState!.validate()) { + print('DEBUG: Validasi form gagal'); + return; + } + + setState(() { + _isResetting = true; + _errorMessage = ''; + }); + + try { + print('DEBUG: Mengirim request reset password ke server'); + final result = await _forgotPasswordService.resetPasswordTailor( + email: _authController.emailController.text, + password: _passwordController.text, + passwordConfirmation: _passwordConfirmationController.text, + pin: _pinController.text, + ); + + print('DEBUG: Response dari server: $result'); + + setState(() => _isResetting = false); + + if (!mounted) return; + + if (result['success']) { + print('DEBUG: Reset password berhasil'); + // Tampilkan dialog sukses + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.check_circle, color: Colors.green), + SizedBox(width: 8), + Text('Berhasil'), + ], + ), + content: const Text( + 'Password berhasil direset. Silakan login dengan password baru.'), + actions: [ + TextButton( + onPressed: () { + print('DEBUG: Menutup dialog dan kembali ke halaman login'); + Navigator.of(context).pop(); // Tutup dialog + Navigator.of(context).pop(); // Kembali ke halaman login + }, + child: const Text('OK'), + ), + ], + ), + ); + } else { + print('DEBUG: Reset password gagal: ${result['message']}'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + } + } catch (e, stackTrace) { + print('ERROR: Terjadi kesalahan saat reset password:'); + print('ERROR: $e'); + print('ERROR: Stack trace:'); + print(stackTrace); + + setState(() { + _isResetting = false; + _errorMessage = 'Terjadi kesalahan: $e'; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + title: const Text( + 'Lupa Password?', + style: TextStyle( + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + centerTitle: true, + ), + body: Center( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Form( + key: _formKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Text( + 'Lupa Password?', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 10), + Text( + _isEmailSent + ? 'Masukkan PIN 6 digit yang telah dikirim ke email Anda' + : 'Masukkan Email yang sudah terdaftar sebagai Tailor', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + const SizedBox(height: 30), + + if (!_isEmailSent) ...[ + CustomTextField( + controller: _authController.emailController, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Email tidak boleh kosong'; + } + if (!value.contains('@')) { + return 'Email tidak valid'; + } + return null; + }, + ), + const SizedBox(height: 20), + CustomButton( + text: 'Kirim', + onPressed: _resetPassword, + isLoading: _isLoading, + ), + ] else ...[ + CustomTextField( + controller: _pinController, + labelText: 'PIN', + hintText: 'Masukkan 6 digit PIN dari email', + maxLength: 6, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + validator: (value) { + if (value == null || value.isEmpty) { + return 'PIN tidak boleh kosong'; + } + if (value.length != 6) { + return 'PIN harus 6 digit'; + } + if (!RegExp(r'^\d+$').hasMatch(value)) { + return 'PIN hanya boleh berisi angka'; + } + return null; + }, + ), + const SizedBox(height: 15), + PasswordField( + controller: _passwordController, + labelText: 'Password Baru', + hintText: 'Minimal 8 karakter', + validator: (value) { + if (value == null || value.isEmpty) { + return 'Password tidak boleh kosong'; + } + if (value.length < 8) { + return 'Password minimal 8 karakter'; + } + return null; + }, + ), + const SizedBox(height: 15), + PasswordField( + controller: _passwordConfirmationController, + labelText: 'Konfirmasi Password', + hintText: 'Masukkan ulang password baru', + validator: (value) { + if (value == null || value.isEmpty) { + return 'Konfirmasi password tidak boleh kosong'; + } + if (value != _passwordController.text) { + return 'Konfirmasi password tidak cocok'; + } + return null; + }, + ), + const SizedBox(height: 20), + CustomButton( + text: 'Reset Password', + onPressed: _submitResetPassword, + isLoading: _isResetting, + ), + ], + + const SizedBox(height: 20), + + // Error message + if (_errorMessage.isNotEmpty) + _buildMessageContainer( + icon: Icons.error, + iconColor: Colors.red[400]!, + backgroundColor: Colors.red[100]!, + textColor: Colors.red[900]!, + message: _errorMessage, + ), + ], + ), + ), + ), + ), + ), + ); + } + + Widget _buildMessageContainer({ + required IconData icon, + required Color iconColor, + required Color backgroundColor, + required Color textColor, + required String message, + }) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Icon( + icon, + color: iconColor, + size: 20, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + message, + style: TextStyle( + fontSize: 12, + color: textColor, + ), + ), + ), + ], + ), + ); + } +} diff --git a/TA_android/lib/pages/auth/login_page.dart b/TA_android/lib/pages/auth/login_page.dart new file mode 100644 index 0000000..6be0b50 --- /dev/null +++ b/TA_android/lib/pages/auth/login_page.dart @@ -0,0 +1,217 @@ +import 'package:flutter/material.dart'; +import '../../core/widgets/custom_text_field.dart'; +import '../../core/widgets/custom_button.dart'; +import '../../core/widgets/password_field.dart'; +import '../../core/controllers/auth_controller.dart'; +import '../../core/routes/routes.dart'; +import 'login_tailor_page.dart'; +import 'forgot_password_customer_page.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({super.key}); + + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + final AuthController _authController = AuthController(); + int _debugTapCount = 0; + final int _requiredTapsForDebug = 7; + DateTime? _lastTapTime; + + void _handleDebugTap() { + final now = DateTime.now(); + + // Reset counter jika taps terlalu lambat (lebih dari 3 detik) + if (_lastTapTime != null && now.difference(_lastTapTime!).inSeconds > 3) { + _debugTapCount = 0; + } + + _lastTapTime = now; + _debugTapCount++; + + if (_debugTapCount >= _requiredTapsForDebug) { + _debugTapCount = 0; // Reset counter + + // Buka halaman debug + Navigator.pushNamed(context, '/debug'); + } + } + + @override + void dispose() { + _authController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Stack( + children: [ + // Background biru dengan logo + Column( + children: [ + Container( + color: const Color(0xFF1A2552), + height: MediaQuery.of(context).size.height * 0.5, + width: double.infinity, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Logo mesin jahit + Image.asset( + 'assets/images/LogoPutih.png', + width: 250, + height: 250, + ), + ], + ), + ), + ), + ], + ), + // Form Login - Di posisikan dengan Positioned di dalam Stack + Positioned( + top: MediaQuery.of(context).size.height * 0.43, + left: 0, + right: 0, + bottom: 0, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 30), + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 10, + spreadRadius: 0, + offset: Offset(0, -2), + ), + ], + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 30), + // Judul Login + GestureDetector( + onTap: _handleDebugTap, + child: const Text( + 'Login Pelanggan', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 20), + // Email field + CustomTextField( + controller: _authController.emailController, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 15), + // Password field + PasswordField( + controller: _authController.passwordController, + labelText: 'Password', + ), + const SizedBox(height: 10), + // Lupa Password & Login Penjahit + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // Lupa Password + GestureDetector( + onTap: () { + // Navigasi ke halaman lupa password customer + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const ForgotPasswordCustomerPage(), + ), + ); + }, + child: const Text( + 'Lupa Password?', + style: TextStyle( + color: Color(0xFF1A2552), + fontSize: 12, + ), + ), + ), + // Login Penjahit + GestureDetector( + onTap: () { + // Navigasi ke halaman login penjahit + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const LoginTailorPage(), + ), + ); + }, + child: const Text( + 'Login Penjahit', + style: TextStyle( + color: Color(0xFF1A2552), + fontSize: 12, + ), + ), + ), + ], + ), + const SizedBox(height: 20), + // Login button + CustomButton( + text: 'Login', + onPressed: () async { + if (_authController.validateLoginInputs(context)) { + // Implementasi login pelanggan + final success = + await _authController.loginCustomer(context); + if (success) { + // Navigasi ke halaman utama customer + Navigator.pushReplacementNamed( + context, AppRoutes.customerHome); + } + } + }, + ), + const SizedBox(height: 20), + // Daftar link + GestureDetector( + onTap: () { + // Navigate to register page + Navigator.pushNamed( + context, AppRoutes.registerCustomer); + }, + child: const Text( + 'Daftar?', + style: TextStyle( + color: Color(0xFF1A2552), + fontSize: 14, + ), + ), + ), + const SizedBox(height: 20), + ], + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/TA_android/lib/pages/auth/login_tailor_page.dart b/TA_android/lib/pages/auth/login_tailor_page.dart new file mode 100644 index 0000000..bced739 --- /dev/null +++ b/TA_android/lib/pages/auth/login_tailor_page.dart @@ -0,0 +1,218 @@ +import 'package:flutter/material.dart'; +import '../../core/widgets/custom_text_field.dart'; +import '../../core/widgets/custom_button.dart'; +import '../../core/widgets/password_field.dart'; +import '../../core/controllers/auth_controller.dart'; +import '../../core/routes/routes.dart'; +import 'forgot_password_tailor_page.dart'; + +class LoginTailorPage extends StatefulWidget { + const LoginTailorPage({super.key}); + + @override + State createState() => _LoginTailorPageState(); +} + +class _LoginTailorPageState extends State { + final AuthController _authController = AuthController(); + bool _isLoading = false; + + @override + void dispose() { + _authController.dispose(); + super.dispose(); + } + + Future _loginTailor(BuildContext context) async { + if (!mounted) return; + + setState(() { + _isLoading = true; + }); + + try { + final result = await _authController.loginTailor(context); + + if (!mounted) return; + + if (result) { + // Navigasi ke halaman utama penjahit setelah login + Navigator.pushNamedAndRemoveUntil( + context, + AppRoutes.tailorHome, + (route) => false, + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + Navigator.pushReplacementNamed(context, AppRoutes.login); + return false; + }, + child: Scaffold( + body: Stack( + children: [ + // Background biru dengan logo + Column( + children: [ + Container( + color: const Color(0xFF1A2552), + height: MediaQuery.of(context).size.height * 0.5, + width: double.infinity, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Logo mesin jahit + Image.asset( + 'assets/images/LogoPutih.png', + width: 250, + height: 250, + ), + ], + ), + ), + ), + ], + ), + // Form Login - Di posisikan dengan Positioned di dalam Stack + Positioned( + top: MediaQuery.of(context).size.height * 0.43, + left: 0, + right: 0, + bottom: 0, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 30), + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 10, + spreadRadius: 0, + offset: Offset(0, -2), + ), + ], + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 30), + // Judul Login + const Text( + 'Login Penjahit', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 20), + // Email field + CustomTextField( + controller: _authController.emailController, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 15), + // Password field + PasswordField( + controller: _authController.passwordController, + labelText: 'Password', + ), + const SizedBox(height: 10), + // Lupa Password & Login Pelanggan + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // Lupa Password + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const ForgotPasswordTailorPage(), + ), + ); + }, + child: const Text( + 'Lupa Password?', + style: TextStyle( + color: Color(0xFF1A2552), + fontSize: 12, + ), + ), + ), + // Login Pelanggan + GestureDetector( + onTap: () { + Navigator.pushReplacementNamed( + context, + AppRoutes.login, + ); + }, + child: const Text( + 'Login Pelanggan', + style: TextStyle( + color: Color(0xFF1A2552), + fontSize: 12, + ), + ), + ), + ], + ), + const SizedBox(height: 20), + // Login button + CustomButton( + text: 'Login', + onPressed: _isLoading + ? () {} + : () => _loginTailor(context), + isLoading: _isLoading, + ), + const SizedBox(height: 20), + // Daftar link + GestureDetector( + onTap: _isLoading + ? null + : () { + Navigator.pushReplacementNamed( + context, + AppRoutes.registerOption, + ); + }, + child: const Text( + 'Daftar?', + style: TextStyle( + color: Color(0xFF1A2552), + fontSize: 14, + ), + ), + ), + const SizedBox(height: 20), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/pages/auth/register_customer_page.dart b/TA_android/lib/pages/auth/register_customer_page.dart new file mode 100644 index 0000000..cdd5583 --- /dev/null +++ b/TA_android/lib/pages/auth/register_customer_page.dart @@ -0,0 +1,542 @@ +import 'package:flutter/material.dart'; +import '../../core/widgets/custom_text_field.dart'; +import '../../core/widgets/custom_button.dart'; +import '../../core/widgets/password_field.dart'; +import '../../core/controllers/auth_controller.dart'; +import '../../core/widgets/location_picker_dialog.dart'; +import '../clothing_category_page.dart'; +import '../auth/login_page.dart'; +// ignore_for_file: avoid_print + +class RegisterCustomerPage extends StatefulWidget { + const RegisterCustomerPage({super.key}); + + @override + State createState() => _RegisterCustomerPageState(); +} + +class _RegisterCustomerPageState extends State { + final AuthController _authController = AuthController(); + bool _isLoading = false; + bool _useLocation = false; + + @override + void initState() { + super.initState(); + // Periksa apakah koordinat sudah diisi + WidgetsBinding.instance.addPostFrameCallback((_) { + if (_authController.latitudeController.text.isNotEmpty && + _authController.longitudeController.text.isNotEmpty) { + setState(() { + _useLocation = true; + }); + } + }); + } + + @override + void dispose() { + _authController.dispose(); + super.dispose(); + } + + // Function to show location picker dialog + void _showLocationPickerDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return LocationPickerDialog( + initialLatitude: _authController.latitudeController.text.isNotEmpty + ? double.tryParse(_authController.latitudeController.text) + : null, + initialLongitude: _authController.longitudeController.text.isNotEmpty + ? double.tryParse(_authController.longitudeController.text) + : null, + isTailor: false, // Dialog untuk pelanggan + onLocationSelected: (latitude, longitude) { + setState(() { + _authController.latitudeController.text = latitude.toString(); + _authController.longitudeController.text = longitude.toString(); + _useLocation = true; + }); + }, + ); + }, + ); + } + + // Tambahkan fungsi untuk menampilkan dialog sukses + void _showSuccessDialog() { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + elevation: 5, + child: Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24), + color: Colors.white, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Header dengan ikon sukses + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: Colors.green.shade50, + shape: BoxShape.circle, + ), + child: Icon( + Icons.check_circle, + color: Colors.green.shade600, + size: 50, + ), + ), + const SizedBox(height: 20), + + // Judul Dialog + const Text( + 'Registrasi Berhasil!', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + + // Pesan utama + Container( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: const Text( + 'Selamat! Akun Anda telah berhasil dibuat. Silakan login untuk melanjutkan.', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Color(0xFF666666), + height: 1.4, + ), + ), + ), + const SizedBox(height: 16), + + // Informasi verifikasi + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue.shade100), + ), + child: Row( + children: [ + Icon( + Icons.mail_outline, + color: Colors.blue.shade700, + size: 24, + ), + const SizedBox(width: 12), + const Expanded( + child: Text( + 'Tolong periksa email Anda untuk verifikasi akun Anda.', + style: TextStyle( + color: Color(0xFF0D47A1), + fontWeight: FontWeight.w500, + fontSize: 14, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 24), + + // Tombol login + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + // Tutup dialog dan navigasi ke halaman login + Navigator.of(context).pop(); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => const LoginPage()), + (route) => false, + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: const Text( + 'Login Sekarang', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + title: const Text( + 'Daftar Akun Pelanggan', + style: TextStyle( + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + centerTitle: true, + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 30), + + // Informasi penting + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.info_outline, + color: Colors.blue.shade700), + const SizedBox(width: 8), + Text( + 'Informasi Pendaftaran', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.blue.shade800, + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + 'Lokasi (koordinat) diperlukan untuk mendaftar sebagai pelanggan. Hal ini membantu kami menemukan penjahit terdekat untuk Anda.', + style: TextStyle( + fontSize: 12, + color: Colors.blue.shade900, + ), + ), + ], + ), + ), + const SizedBox(height: 20), + + // === INFORMASI AKUN === + const Text( + 'Informasi Akun', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + + // Email field + CustomTextField( + controller: _authController.emailController, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 20), + + // Password field + PasswordField( + controller: _authController.passwordController, + labelText: 'Password', + hintText: 'Minimal 8 karakter', + ), + const SizedBox(height: 20), + + // Konfirmasi Password field + PasswordField( + controller: _authController.confirmPasswordController, + labelText: 'Konfirmasi Password', + ), + const SizedBox(height: 30), + + // === INFORMASI PRIBADI === + const Text( + 'Informasi Pribadi', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + + // Nama field + CustomTextField( + controller: _authController.nameController, + labelText: 'Nama', + ), + const SizedBox(height: 20), + + // No Handphone field + CustomTextField( + controller: _authController.phoneController, + labelText: 'No Handphone', + keyboardType: TextInputType.phone, + ), + const SizedBox(height: 20), + + // Alamat field + CustomTextField( + controller: _authController.addressController, + labelText: 'Alamat', + maxLines: 2, + ), + const SizedBox(height: 16), + + // Lokasi (Peta) + Container( + decoration: BoxDecoration( + border: Border.all( + color: _useLocation + ? const Color(0xFF1A2552) + : Colors.red + .shade300, // Red border jika belum diatur + ), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + children: [ + // Header lokasi + Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Baris pertama: Judul dan tombol + Row( + children: [ + Icon( + Icons.location_on_outlined, + color: _useLocation + ? const Color(0xFF1A2552) + : Colors.red + .shade400, // Red icon jika belum diatur + ), + const SizedBox(width: 8), + Expanded( + child: Row( + children: [ + Text( + 'Lokasi Anda', + style: TextStyle( + fontWeight: FontWeight.w500, + color: _useLocation + ? const Color(0xFF1A2552) + : Colors.red + .shade400, // Red text jika belum diatur + ), + ), + const SizedBox(width: 4), + Text( + '(Wajib)', + style: TextStyle( + fontSize: 12, + color: Colors.red.shade400, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + const SizedBox(width: 8), + ElevatedButton.icon( + onPressed: _showLocationPickerDialog, + icon: const Icon(Icons.map_outlined, + size: 16), + label: Text( + _useLocation ? 'Ubah' : 'Pilih'), + style: ElevatedButton.styleFrom( + backgroundColor: _useLocation + ? const Color(0xFF1A2552) + : Colors.red + .shade400, // Red button jika belum diatur + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + minimumSize: const Size(60, 30), + textStyle: + const TextStyle(fontSize: 12), + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(8), + ), + ), + ), + ], + ), + // Baris kedua: Informasi koordinat + const SizedBox(height: 4), + if (_useLocation && + _authController + .latitudeController.text.isNotEmpty) + Text( + 'Lat: ${double.parse(_authController.latitudeController.text).toStringAsFixed(6)}, Lng: ${double.parse(_authController.longitudeController.text).toStringAsFixed(6)}', + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ) + else + Text( + 'Belum diatur - diperlukan untuk menemukan penjahit terdekat', + style: TextStyle( + fontSize: 12, + color: Colors.red.shade300, + ), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 20), + ], + ), + ), + ), + // Lanjut button + Padding( + padding: const EdgeInsets.only(bottom: 20.0), + child: CustomButton( + text: 'Lanjut', + isLoading: _isLoading, + onPressed: () async { + setState(() { + _isLoading = true; + }); + + // Validasi input + if (!_authController.validateRegistrationInputs(context)) { + setState(() { + _isLoading = false; + }); + return; + } + + // Update flag lokasi berdasarkan nilai koordinat + if (_authController.latitudeController.text.isNotEmpty && + _authController.longitudeController.text.isNotEmpty) { + setState(() { + _useLocation = true; + }); + } + + // Validasi tambahan untuk lokasi jika belum diatur + if (!_useLocation) { + // Tampilkan dialog konfirmasi + bool continueWithoutLocation = await _authController + .showNoLocationConfirmationDialog(context); + if (!continueWithoutLocation) { + setState(() { + _isLoading = false; + }); + return; + } + } + + // Cek dan log koordinat sebelum navigasi + print( + 'Koordinat yang akan diteruskan ke ClothingCategoryPage:'); + print( + 'Latitude: ${_authController.latitudeController.text}'); + print( + 'Longitude: ${_authController.longitudeController.text}'); + + // Lanjut ke halaman pemilihan model jahit + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ClothingCategoryPage( + email: _authController.emailController.text, + name: _authController.nameController.text, + phone: _authController.phoneController.text, + address: _authController.addressController.text, + password: _authController.passwordController.text, + latitude: + _authController.latitudeController.text.isNotEmpty + ? double.tryParse( + _authController.latitudeController.text) + : null, + longitude: _authController + .longitudeController.text.isNotEmpty + ? double.tryParse( + _authController.longitudeController.text) + : null, + isTailor: false, // Menandakan ini adalah pelanggan + onRegistrationSuccess: () { + // Tampilkan dialog sukses setelah registrasi berhasil + _showSuccessDialog(); + }, + ), + ), + ).then((_) { + setState(() { + _isLoading = false; + }); + }); + }, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/TA_android/lib/pages/auth/register_tailor_page.dart b/TA_android/lib/pages/auth/register_tailor_page.dart new file mode 100644 index 0000000..1da3bbb --- /dev/null +++ b/TA_android/lib/pages/auth/register_tailor_page.dart @@ -0,0 +1,453 @@ +import 'package:flutter/material.dart'; +import '../../core/widgets/custom_text_field.dart'; +import '../../core/widgets/custom_button.dart'; +import '../../core/widgets/password_field.dart'; +import '../../core/controllers/auth_controller.dart'; +import '../../core/widgets/location_picker_dialog.dart'; +import '../clothing_category_page.dart'; + +class RegisterTailorPage extends StatefulWidget { + const RegisterTailorPage({super.key}); + + @override + State createState() => _RegisterTailorPageState(); +} + +class _RegisterTailorPageState extends State { + final AuthController _authController = AuthController(); + bool _isLoading = false; + bool _useLocation = + false; // untuk mengontrol apakah menggunakan lokasi atau tidak + + @override + void initState() { + super.initState(); + // Periksa apakah koordinat sudah diisi + WidgetsBinding.instance.addPostFrameCallback((_) { + if (_authController.latitudeController.text.isNotEmpty && + _authController.longitudeController.text.isNotEmpty) { + setState(() { + _useLocation = true; + }); + } + }); + } + + @override + void dispose() { + _authController.dispose(); + super.dispose(); + } + + // Function to show location picker dialog + void _showLocationPickerDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return LocationPickerDialog( + initialLatitude: _authController.latitudeController.text.isNotEmpty + ? double.tryParse(_authController.latitudeController.text) + : null, + initialLongitude: _authController.longitudeController.text.isNotEmpty + ? double.tryParse(_authController.longitudeController.text) + : null, + isTailor: true, // Dialog untuk penjahit + onLocationSelected: (latitude, longitude) { + setState(() { + _authController.latitudeController.text = latitude.toString(); + _authController.longitudeController.text = longitude.toString(); + _useLocation = true; + }); + }, + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + resizeToAvoidBottomInset: true, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + title: const Text( + 'Daftar Akun Penjahit', + style: TextStyle( + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + centerTitle: true, + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + physics: const ClampingScrollPhysics(), + keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 20), + + // === INFORMASI AKUN === + const Text( + 'Informasi Akun', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + + // Email field + CustomTextField( + controller: _authController.emailController, + labelText: 'Email', + keyboardType: TextInputType.emailAddress, + ), + const SizedBox(height: 20), + + // Password field + PasswordField( + controller: _authController.passwordController, + labelText: 'Password', + hintText: 'Minimal 8 karakter', + ), + const SizedBox(height: 20), + + // Konfirmasi Password field + PasswordField( + controller: _authController.confirmPasswordController, + labelText: 'Konfirmasi Password', + ), + const SizedBox(height: 30), + + // === INFORMASI PRIBADI === + const Text( + 'Informasi Pribadi', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + + // Nama field + CustomTextField( + controller: _authController.nameController, + labelText: 'Nama', + ), + const SizedBox(height: 20), + + // No Handphone field + CustomTextField( + controller: _authController.phoneController, + labelText: 'No Handphone', + keyboardType: TextInputType.phone, + ), + const SizedBox(height: 30), + + // === INFORMASI TOKO === + const Text( + 'Informasi Toko', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + + + + // Deskripsi Toko field + CustomTextField( + controller: _authController.shopDescriptionController, + labelText: 'Deskripsi Toko', + maxLines: 3, + hintText: + 'Jelaskan secara singkat tentang toko/jasa jahit Anda', + ), + const SizedBox(height: 20), + + + + // Alamat field + CustomTextField( + controller: _authController.addressController, + labelText: 'Alamat Toko', + maxLines: 2, + ), + const SizedBox(height: 16), + + // Lokasi Toko (Peta) + Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + children: [ + // Header lokasi + Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Baris pertama: Judul dan tombol + Row( + children: [ + Icon( + Icons.location_on_outlined, + color: _useLocation + ? const Color(0xFF1A2552) + : Colors.grey, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Lokasi Toko', + style: TextStyle( + fontWeight: FontWeight.w500, + color: _useLocation + ? const Color(0xFF1A2552) + : Colors.grey.shade700, + ), + ), + ), + const SizedBox(width: 8), + ElevatedButton.icon( + onPressed: _showLocationPickerDialog, + icon: const Icon(Icons.map_outlined, + size: 16), + label: Text( + _useLocation ? 'Ubah' : 'Pilih'), + style: ElevatedButton.styleFrom( + backgroundColor: + const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + minimumSize: const Size(60, 30), + textStyle: + const TextStyle(fontSize: 12), + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(8), + ), + ), + ), + ], + ), + // Baris kedua: Informasi koordinat + const SizedBox(height: 4), + if (_useLocation && + _authController + .latitudeController.text.isNotEmpty) + Text( + 'Lat: ${double.parse(_authController.latitudeController.text).toStringAsFixed(6)}, Lng: ${double.parse(_authController.longitudeController.text).toStringAsFixed(6)}', + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ) + else + Text( + 'Belum diatur', + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade500, + ), + ), + ], + ), + ), + + // Preview peta (jika lokasi sudah dipilih) + if (_useLocation && + _authController + .latitudeController.text.isNotEmpty) + Container( + height: 120, + width: double.infinity, + margin: + const EdgeInsets.fromLTRB(12, 0, 12, 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: + Border.all(color: Colors.grey.shade300), + color: const Color(0xFFE0E0E0), + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.location_on, + color: Color(0xFF1A2552), + size: 32, + ), + const SizedBox(height: 8), + Text( + 'Lat: ${double.parse(_authController.latitudeController.text).toStringAsFixed(6)}\nLng: ${double.parse(_authController.longitudeController.text).toStringAsFixed(6)}', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade700, + ), + ), + ], + ), + ), + ), + ], + ), + ), + + const SizedBox(height: 30), + ], + ), + ), + ), + // Lanjut button + Padding( + padding: const EdgeInsets.only(bottom: 20.0), + child: CustomButton( + text: 'Lanjut', + isLoading: _isLoading, + onPressed: () { + setState(() { + _isLoading = true; + }); + + // Validasi input tanpa melakukan registrasi + if (_validateBasicInfo(context)) { + // Update flag lokasi berdasarkan nilai koordinat + if (_authController.latitudeController.text.isNotEmpty && + _authController.longitudeController.text.isNotEmpty) { + setState(() { + _useLocation = true; + }); + } + + // Lanjut ke halaman pemilihan spesialisasi + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ClothingCategoryPage( + email: _authController.emailController.text, + name: _authController.nameController.text, + phone: _authController.phoneController.text, + address: _authController.addressController.text, + password: _authController.passwordController.text, + storeName: _authController.nameController.text, + experience: '0', + shopDescription: + _authController.shopDescriptionController.text, + latitude: _authController + .latitudeController.text.isNotEmpty + ? double.tryParse( + _authController.latitudeController.text) + : null, + longitude: _authController + .longitudeController.text.isNotEmpty + ? double.tryParse( + _authController.longitudeController.text) + : null, + isTailor: true, // Menandakan ini adalah penjahit + ), + ), + ).then((_) { + setState(() { + _isLoading = false; + }); + }); + } else { + setState(() { + _isLoading = false; + }); + } + }, + ), + ), + ], + ), + ), + ), + ); + } + + // Metode untuk validasi data dasar + bool _validateBasicInfo(BuildContext context) { + // Cek field yang kosong + if (_authController.emailController.text.isEmpty || + _authController.nameController.text.isEmpty || + + _authController.shopDescriptionController.text.isEmpty || + + _authController.phoneController.text.isEmpty || + _authController.addressController.text.isEmpty || + _authController.passwordController.text.isEmpty || + _authController.confirmPasswordController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Semua field harus diisi'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + // Validasi password minimal 8 karakter + if (_authController.passwordController.text.length < 8) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Password harus minimal 8 karakter'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + // Validasi password dan konfirmasi password + if (_authController.passwordController.text != + _authController.confirmPasswordController.text) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Password dan konfirmasi password harus sama'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + // Validasi format email sederhana + if (!_authController.emailController.text.contains('@') || + !_authController.emailController.text.contains('.')) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Format email tidak valid'), + backgroundColor: Colors.red, + ), + ); + return false; + } + + return true; + } +} diff --git a/TA_android/lib/pages/clothing_category_page.dart b/TA_android/lib/pages/clothing_category_page.dart new file mode 100644 index 0000000..3c14913 --- /dev/null +++ b/TA_android/lib/pages/clothing_category_page.dart @@ -0,0 +1,678 @@ +import 'package:flutter/material.dart'; +import '../core/widgets/category_card.dart'; +import '../core/controllers/auth_controller.dart'; +import '../core/controllers/category_controller.dart'; +import '../core/widgets/custom_button.dart'; +import '../core/services/api_service.dart'; +// ignore_for_file: avoid_print + +class ClothingCategoryPage extends StatefulWidget { + final String email; + final String name; + final String phone; + final String address; + final String password; + final String? storeName; + final String? experience; + final String? shopDescription; + final double? latitude; + final double? longitude; + final bool isTailor; + final VoidCallback? onRegistrationSuccess; + + const ClothingCategoryPage({ + super.key, + required this.email, + required this.name, + required this.phone, + required this.address, + required this.password, + this.storeName, + this.experience, + this.shopDescription, + this.latitude, + this.longitude, + this.isTailor = false, + this.onRegistrationSuccess, + }); + + @override + State createState() => _ClothingCategoryPageState(); +} + +class _ClothingCategoryPageState extends State { + final AuthController _authController = AuthController(); + final CategoryController _categoryController = CategoryController(); + bool _isLoading = false; + + @override + void initState() { + super.initState(); + _loadFormData(); + _loadSpecializations(); + } + + void _loadFormData() { + // Transfer data from widget to auth controller + _authController.emailController.text = widget.email; + _authController.nameController.text = widget.name; + _authController.phoneController.text = widget.phone; + _authController.addressController.text = widget.address; + _authController.passwordController.text = widget.password; + _authController.confirmPasswordController.text = widget.password; + + // Load coordinates for both tailor and customer if available + if (widget.latitude != null) { + _authController.latitudeController.text = widget.latitude.toString(); + print('Loading latitude: ${widget.latitude}'); + } + + if (widget.longitude != null) { + _authController.longitudeController.text = widget.longitude.toString(); + print('Loading longitude: ${widget.longitude}'); + } + + if (widget.isTailor) { + _authController.storeNameController.text = widget.storeName ?? ''; + _authController.experienceController.text = widget.experience ?? ''; + _authController.shopDescriptionController.text = + widget.shopDescription ?? ''; + } + } + + Future _loadSpecializations() async { + setState(() { + _isLoading = true; + }); + + try { + // Menggunakan ApiService untuk mendapatkan daftar spesialisasi + final specializations = await ApiService.getSpecializations(); + print('Loaded ${specializations.length} specializations to display'); + + if (mounted) { + setState(() { + _authController.availableSpecializations = specializations; + // Inisialisasi data kategori dari API + _categoryController.initializeFromApi(specializations); + }); + } + } catch (e) { + print('Error loading specializations: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal memuat spesialisasi: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + void _handleRegistrationSuccess() { + if (widget.onRegistrationSuccess != null) { + widget.onRegistrationSuccess!(); + } else { + // Default behavior jika callback tidak disediakan + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + elevation: 5, + child: Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24), + color: Colors.white, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Header dengan ikon sukses + Stack( + alignment: Alignment.center, + children: [ + Container( + width: 100, + height: 100, + decoration: BoxDecoration( + color: Colors.green.shade50, + shape: BoxShape.circle, + ), + ), + Icon( + Icons.check_circle, + color: Colors.green.shade600, + size: 70, + ), + ], + ), + const SizedBox(height: 24), + + // Judul Dialog + Text( + 'Registrasi ${widget.isTailor ? 'Penjahit' : 'Pelanggan'} Berhasil!', + style: const TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + + // Pesan utama + Text( + widget.isTailor + ? 'Selamat! Akun penjahit Anda telah berhasil dibuat dan siap digunakan.' + : 'Selamat! Akun Anda telah berhasil dibuat.', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 16, + color: Color(0xFF666666), + height: 1.4, + ), + ), + const SizedBox(height: 16), + + // Informasi verifikasi + Container( + margin: const EdgeInsets.symmetric(vertical: 8), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue.shade100), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon( + Icons.mail_outline, + color: Colors.blue.shade700, + size: 24, + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Verifikasi Email', + style: TextStyle( + color: Color(0xFF0D47A1), + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(height: 4), + Text( + 'Kami telah mengirimkan email verifikasi ke ${_authController.emailController.text}. Harap periksa email Anda dan klik tautan verifikasi untuk mengaktifkan akun Anda.', + style: const TextStyle( + color: Color(0xFF0D47A1), + fontSize: 14, + ), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 24), + + // Tombol login + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + Navigator.of(context).pop(); + // Navigasi ke halaman login + Navigator.pushNamedAndRemoveUntil( + context, + widget.isTailor ? '/login-tailor' : '/login', + (route) => false, + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: const Text( + 'LOGIN SEKARANG', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } + } + + // Tampilkan dialog error spesialisasi + void _showSpecializationErrorDialog(BuildContext context, String userType) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Row( + children: [ + Icon(Icons.warning_amber_rounded, color: Colors.amber, size: 28), + SizedBox(width: 8), + Text( + 'Spesialisasi Diperlukan', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + userType == "penjahit" + ? 'Anda belum memilih spesialisasi untuk akun penjahit Anda.' + : 'Anda belum memilih model jahit kesukaan.', + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 12), + Text( + userType == "penjahit" + ? 'Harap pilih minimal satu spesialisasi untuk membuat profil penjahit yang lengkap dan memudahkan pelanggan menemukan jasa Anda.' + : 'Harap pilih minimal satu model jahit kesukaan untuk membantu kami merekomendasikan penjahit yang sesuai dengan preferensi Anda.', + style: TextStyle(color: Colors.grey[700], fontSize: 14), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text( + 'MENGERTI', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final String pageTitle = widget.isTailor + ? 'Spesialis Kemampuan Kamu?' + : 'Apa Model Jahit Kesukaan Kamu?'; + + return Scaffold( + backgroundColor: Colors.white, + resizeToAvoidBottomInset: true, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + title: Text( + pageTitle, + style: const TextStyle( + color: Colors.black, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + centerTitle: true, + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + children: [ + Expanded( + child: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _buildSpecializationsList(), + ), + // Daftar button + Container( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom > 0 ? + 10 : 20.0, + top: 10, + ), + child: CustomButton( + text: 'Daftar', + isLoading: _isLoading, + onPressed: () async { + setState(() { + _isLoading = true; + }); + + try { + if (widget.isTailor) { + // Jika tidak ada spesialisasi yang dipilih + if (_authController.selectedSpecializations.isEmpty) { + // Tampilkan dialog error spesialisasi + _showSpecializationErrorDialog(context, "penjahit"); + return; + } + + // Log data registrasi + print( + 'Memulai proses registrasi penjahit dengan spesialisasi:'); + print('Email: ${_authController.emailController.text}'); + print('Nama: ${_authController.nameController.text}'); + print( + 'Spesialisasi dipilih: ${_authController.selectedSpecializations}'); + + // Verifikasi bahwa koordinat terisi jika latitude/longitude dari halaman sebelumnya tersedia + if (widget.latitude != null && + _authController.latitudeController.text.isEmpty) { + print( + 'WARNING: Latitude hilang saat proses registrasi! widget.latitude: ${widget.latitude}'); + _authController.latitudeController.text = + widget.latitude.toString(); + } + + if (widget.longitude != null && + _authController.longitudeController.text.isEmpty) { + print( + 'WARNING: Longitude hilang saat proses registrasi! widget.longitude: ${widget.longitude}'); + _authController.longitudeController.text = + widget.longitude.toString(); + } + + // Proses registrasi penjahit + final success = + await _authController.registerTailor(context); + if (success) { + print( + 'Registrasi berhasil, menampilkan dialog sukses'); + _handleRegistrationSuccess(); + } else { + print( + 'Registrasi gagal, tetap pada halaman saat ini'); + // Dialog error registrasi ditangani oleh AuthController + } + } else { + // Proses registrasi customer + if (_authController.selectedSpecializations.isEmpty) { + // Tampilkan dialog error spesialisasi + _showSpecializationErrorDialog(context, "pelanggan"); + return; + } + + // Log data registrasi pelanggan + print( + 'Memulai proses registrasi pelanggan dengan spesialisasi:'); + print('Email: ${_authController.emailController.text}'); + print('Nama: ${_authController.nameController.text}'); + print( + 'Spesialisasi dipilih: ${_authController.selectedSpecializations}'); + print( + 'Koordinat Latitude: ${_authController.latitudeController.text}'); + print( + 'Koordinat Longitude: ${_authController.longitudeController.text}'); + + // Verifikasi bahwa koordinat terisi jika latitude/longitude dari halaman sebelumnya tersedia + if (widget.latitude != null && + _authController.latitudeController.text.isEmpty) { + print( + 'WARNING: Latitude hilang saat proses registrasi! widget.latitude: ${widget.latitude}'); + _authController.latitudeController.text = + widget.latitude.toString(); + } + + if (widget.longitude != null && + _authController.longitudeController.text.isEmpty) { + print( + 'WARNING: Longitude hilang saat proses registrasi! widget.longitude: ${widget.longitude}'); + _authController.longitudeController.text = + widget.longitude.toString(); + } + + // Proses registrasi pelanggan + final success = + await _authController.registerCustomer(context); + if (success) { + print( + 'Registrasi pelanggan berhasil, navigasi ke halaman login'); + _handleRegistrationSuccess(); + } else { + print( + 'Registrasi pelanggan gagal, tetap pada halaman saat ini'); + // Dialog error registrasi ditangani oleh AuthController + } + } + } finally { + setState(() { + _isLoading = false; + }); + } + }, + ), + ), + ], + ), + ), + ), + ); + } + + Widget _buildSpecializationsList() { + if (widget.isTailor) { + // Tampilkan list spesialisasi dari API + if (_authController.availableSpecializations.isEmpty) { + return const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.warning_amber_rounded, + size: 48, + color: Colors.amber, + ), + SizedBox(height: 16), + Text( + 'Tidak ada spesialisasi tersedia', + style: TextStyle(fontSize: 16), + textAlign: TextAlign.center, + ), + SizedBox(height: 8), + Text( + 'Silakan coba lagi nanti atau hubungi admin', + style: TextStyle(fontSize: 14, color: Colors.grey), + textAlign: TextAlign.center, + ), + ], + ), + ); + } + + return ListView.builder( + padding: const EdgeInsets.symmetric(vertical: 16), + itemCount: _categoryController.categoryGroups.length, + itemBuilder: (context, groupIndex) { + final categoryName = _categoryController.categoryGroups[groupIndex]; + final specializations = + _categoryController.apiCategories[categoryName] ?? []; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 8.0, right: 8.0, top: 16.0, bottom: 8.0), + child: Text( + categoryName, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ), + SizedBox( + height: 110, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: specializations.length, + padding: const EdgeInsets.symmetric(horizontal: 12.0), + itemBuilder: (context, index) { + final spec = specializations[index]; + final id = spec['id'] as int; + final name = spec['name'] as String; + final photoUrl = spec['fullPhotoUrl'] as String?; + final isSelected = + _authController.selectedSpecializations.contains(id); + + // Debug logging + print('=== CategoryCard Debug Info ==='); + print('Category Name: $name'); + print( + 'Image Path: ${photoUrl ?? 'assets/images/tailor_default.png'}'); + + // Determine if it's a network image based on URL pattern + final bool isNetworkImg = photoUrl != null && + (photoUrl.startsWith('http://') || + photoUrl.startsWith('https://')); + + print('Is Network Image: $isNetworkImg'); + print('Selected: $isSelected'); + print('============================='); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: CategoryCard( + imagePath: + photoUrl ?? 'assets/images/tailor_default.png', + categoryName: name, + isSelected: isSelected, + isNetworkImage: isNetworkImg, + onTap: () { + setState(() { + _authController.toggleSpecialization(id); + }); + }, + ), + ); + }, + ), + ), + ], + ); + }, + ); + } else { + // Menggunakan data dari API untuk tampilan kategori + if (_categoryController.apiCategories.isEmpty) { + return const Center( + child: Text('Tidak ada kategori yang tersedia'), + ); + } + + return ListView.builder( + padding: const EdgeInsets.symmetric(vertical: 16), + itemCount: _categoryController.categoryGroups.length, + itemBuilder: (context, groupIndex) { + final categoryName = _categoryController.categoryGroups[groupIndex]; + final specializations = + _categoryController.apiCategories[categoryName] ?? []; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 8.0, right: 8.0, top: 16.0, bottom: 8.0), + child: Text( + categoryName, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ), + SizedBox( + height: 160, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: specializations.length, + itemBuilder: (context, index) { + final spec = specializations[index]; + final id = spec['id'] as int; + final name = spec['name'] as String; + final photoUrl = spec['fullPhotoUrl'] as String?; + final isSelected = + _authController.selectedSpecializations.contains(id); + + // Debug logging + print('=== CategoryCard Debug Info ==='); + print('Category Name: $name'); + print( + 'Image Path: ${photoUrl ?? 'assets/images/tailor_default.png'}'); + + // Determine if it's a network image based on URL pattern + final bool isNetworkImg = photoUrl != null && + (photoUrl.startsWith('http://') || + photoUrl.startsWith('https://')); + + print('Is Network Image: $isNetworkImg'); + print('Selected: $isSelected'); + print('============================='); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: CategoryCard( + imagePath: + photoUrl ?? 'assets/images/tailor_default.png', + categoryName: name, + isSelected: isSelected, + isNetworkImage: isNetworkImg, + onTap: () { + setState(() { + _authController.toggleSpecialization(id); + }); + }, + ), + ); + }, + ), + ), + ], + ); + }, + ); + } + } +} diff --git a/TA_android/lib/pages/costumer/home/booking_page.dart b/TA_android/lib/pages/costumer/home/booking_page.dart new file mode 100644 index 0000000..9701000 --- /dev/null +++ b/TA_android/lib/pages/costumer/home/booking_page.dart @@ -0,0 +1,1132 @@ +import 'package:flutter/material.dart'; +import 'dart:io'; +import 'package:image_picker/image_picker.dart'; +import 'package:permission_handler/permission_handler.dart'; +import '../../../core/routes/routes.dart'; +import '../../../core/services/booking_service.dart'; +// ignore_for_file: avoid_print + +// Import widget-widget terpisah +import '../../../core/widgets/dropdown_field.dart'; +import '../../../core/widgets/image_upload_field.dart'; +import '../../../core/widgets/multiline_text_field.dart'; +import '../../../core/widgets/label_text.dart'; +import '../../../core/widgets/custom_button.dart'; +import '../../../core/services/api_service.dart'; + +//Halaman Booking + +class BookingPage extends StatefulWidget { + final int tailorId; + final String tailorName; + final String? tailorImage; + + const BookingPage({ + super.key, + required this.tailorId, + required this.tailorName, + this.tailorImage, + }); + + @override + State createState() => _BookingPageState(); +} + +class _BookingPageState extends State { + String _selectedDate = 'Pilih Tanggal'; + String _selectedTime = 'Pilih Jam Temu'; + String _selectedService = 'Pilih Jenis Layanan'; + String _selectedCategory = 'Pilih Kategori'; + String _selectedPaymentMethod = 'transfer_bank'; // Default payment method + String _imageDescription = 'Belum ada foto'; + final String _notes = ''; + File? _selectedImage; + final _picker = ImagePicker(); + final _notesController = TextEditingController(); + + Future _requestPermission(Permission permission) async { + if (await permission.isGranted) { + return true; + } else { + if (await permission.isPermanentlyDenied) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + 'Izin galeri ditolak permanen. Buka pengaturan untuk mengaktifkannya.'), + backgroundColor: Colors.red, + duration: Duration(seconds: 5), + ), + ); + + final shouldOpenSettings = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Izin Diperlukan'), + content: const Text( + 'Untuk memilih gambar dari galeri, izin penyimpanan diperlukan. Buka pengaturan untuk memberikan izin?'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Batal'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: const Text('Buka Pengaturan'), + ), + ], + ), + ) ?? + false; + + if (shouldOpenSettings) { + await openAppSettings(); + } + return false; + } + + var result = await permission.request(); + return result == PermissionStatus.granted; + } + } + + Future _pickImage(bool isCamera) async { + Navigator.pop(context); + + try { + bool hasPermission = false; + + if (isCamera) { + // Untuk kamera + hasPermission = await _requestPermission(Permission.camera); + } else { + // Penanganan khusus untuk galeri - coba semua izin yang mungkin diperlukan + // Cek Android versi + bool isAndroid13OrAbove = await _isAndroid13OrAbove(); + + if (isAndroid13OrAbove) { + // Android 13+ menggunakan READ_MEDIA_IMAGES + hasPermission = await _requestPermission(Permission.photos); + } else { + // Android 12 ke bawah menggunakan READ_EXTERNAL_STORAGE + hasPermission = await _requestPermission(Permission.storage); + } + + // Jika izin masih ditolak, coba cara alternatif + if (!hasPermission) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mencoba cara lain untuk mengakses galeri...'), + backgroundColor: Colors.blue, + duration: Duration(seconds: 2), + ), + ); + + // Coba langsung akses picker tanpa memeriksa izin + hasPermission = true; + } + } + + if (!hasPermission) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + 'Izin ditolak. Silakan aktifkan izin di pengaturan aplikasi.'), + backgroundColor: Colors.red, + duration: Duration(seconds: 4), + ), + ); + return; + } + + // Tampilkan loading dialog + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return const Dialog( + child: Padding( + padding: EdgeInsets.all(20.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircularProgressIndicator(), + SizedBox(width: 20), + Text("Memuat..."), + ], + ), + ), + ); + }, + ); + + // Gunakan try-catch untuk setiap operasi picker + XFile? pickedFile; + try { + if (isCamera) { + pickedFile = await _picker.pickImage( + source: ImageSource.camera, + imageQuality: 80, + ); + } else { + pickedFile = await _picker.pickImage( + source: ImageSource.gallery, + imageQuality: 80, + ); + } + } catch (e) { + print('Error pada picker: $e'); + // Tutup dialog loading jika masih ada + if (Navigator.canPop(context)) { + Navigator.pop(context); + } + + // Coba pendekatan alternatif jika pendekatan utama gagal + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mencoba metode alternatif...'), + duration: Duration(seconds: 1), + ), + ); + + // Coba dengan picker lain atau pendekatan alternatif + try { + if (!isCamera) { + // Hanya untuk galeri, coba dengan lowered permission + pickedFile = await _picker.pickImage( + source: ImageSource.gallery, + imageQuality: 60, // Quality lebih rendah + requestFullMetadata: false, // Jangan minta metadata penuh + ); + } + } catch (secondError) { + print('Error pada pendekatan alternatif: $secondError'); + } + } + + // Tutup dialog loading + if (Navigator.canPop(context)) { + Navigator.pop(context); + } + + // Proses hasil gambar jika ada + if (pickedFile != null) { + setState(() { + _selectedImage = File(pickedFile!.path); + _imageDescription = isCamera + ? 'Foto dari kamera dipilih' + : 'Foto dari galeri dipilih'; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + isCamera + ? 'Foto berhasil diambil dengan kamera' + : 'Foto berhasil dipilih dari galeri', + ), + backgroundColor: Colors.green, + ), + ); + } + } catch (e) { + // Tutup dialog loading jika masih ada + if (Navigator.canPop(context)) { + Navigator.pop(context); + } + + print('Error umum: $e'); + _showErrorDialog(e.toString()); + } + } + + Future _isAndroid13OrAbove() async { + // Ini hanya implementasi sederhana, dalam praktiknya Anda perlu + // menggunakan platform channel untuk mendapatkan versi Android yang akurat + try { + if (Theme.of(context).platform == TargetPlatform.android) { + // Asumsi Android 13+ untuk saat ini + // Dalam implementasi nyata, Anda perlu mendapatkan SDK version sebenarnya + return true; + } + } catch (e) { + print('Error checking Android version: $e'); + } + return false; + } + + void _showErrorDialog(String errorMessage) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Terjadi Kesalahan'), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text('Detail error: $errorMessage'), + const SizedBox(height: 10), + const Text('Solusi yang bisa dicoba:'), + const SizedBox(height: 5), + const Text( + '1. Periksa izin penyimpanan di pengaturan aplikasi'), + const Text('2. Pastikan aplikasi memiliki akses ke galeri'), + const Text('3. Coba gunakan kamera sebagai alternatif'), + const Text('4. Restart aplikasi dan coba lagi'), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Tutup'), + ), + TextButton( + onPressed: () async { + Navigator.of(context).pop(); + await openAppSettings(); + }, + child: const Text('Buka Pengaturan'), + ), + ], + ); + }, + ); + } + + void _selectImage() { + FocusScope.of(context).unfocus(); + + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + title: const Text('Pilih Sumber Foto'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(10), + ), + child: + const Icon(Icons.photo_library, color: Color(0xFF1A2552)), + ), + title: const Text('Galeri'), + subtitle: const Text('Pilih foto dari galeri'), + onTap: () => _pickImage(false), + ), + const Divider(), + ListTile( + leading: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.green.shade50, + borderRadius: BorderRadius.circular(10), + ), + child: const Icon(Icons.camera_alt, color: Color(0xFF1A2552)), + ), + title: const Text('Kamera'), + subtitle: const Text('Ambil foto dengan kamera'), + onTap: () => _pickImage(true), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Batal'), + ), + ], + ); + }, + ); + } + + void _showPaymentMethodOptions() { + showModalBottomSheet( + context: context, + builder: (context) { + return Container( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Pilih Metode Pembayaran', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + _buildPaymentOption('transfer_bank', 'Transfer Bank'), + _buildPaymentOption('cod', 'Cash on Delivery (COD)'), + ], + ), + ); + }, + ); + } + + Widget _buildPaymentOption(String value, String title) { + return ListTile( + title: Text(title), + trailing: _selectedPaymentMethod == value + ? const Icon(Icons.check_circle, color: Color(0xFF1A2552)) + : null, + onTap: () { + setState(() { + _selectedPaymentMethod = value; + }); + Navigator.pop(context); + }, + ); + } + + // Menampilkan dialog berhasil booking dengan kode transaksi + void _showBookingSuccessDialog(String transactionCode) { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 8, + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Color(0xFFF8F9FF), Colors.white], + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Success Animation/Icon + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: const Color(0xFFE8F5E9), + borderRadius: BorderRadius.circular(40), + ), + child: const Icon( + Icons.check_circle, + color: Color(0xFF2E7D32), + size: 60, + ), + ), + const SizedBox(height: 16), + + // Title + const Text( + 'Booking Berhasil', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 20), + + // Transaction Code + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + decoration: BoxDecoration( + color: const Color(0xFFEEF2FF), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: const Color(0xFFD0D9FF)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Kode Transaksi:', + style: TextStyle( + fontSize: 12, + color: Color(0xFF6B7280), + ), + ), + const SizedBox(height: 4), + Text( + transactionCode, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + letterSpacing: 0.5, + ), + ), + ], + ), + ), + const SizedBox(height: 16), + + // Message + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xFFFEF9E7), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: const Color(0xFFFCE8A8)), + ), + child: const Row( + children: [ + Icon( + Icons.info_outline, + color: Color(0xFFF5B100), + size: 24, + ), + SizedBox(width: 10), + Expanded( + child: Text( + 'Pembayaran akan dilakukan setelah penjahit menentukan harga.', + style: TextStyle( + fontSize: 13, + color: Color(0xFF5F4C00), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 24), + + // OK Button + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); // Tutup dialog + Navigator.pushNamedAndRemoveUntil( + context, + AppRoutes.customerHome, + (route) => false, + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1E3A8A), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 2, + ), + child: const Text( + 'OK', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ); + } + + // Menampilkan dialog error jadwal tidak tersedia + void _showScheduleNotAvailableDialog(String errorMessage) { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 8, + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Color(0xFFFFF8F0), Colors.white], + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Warning Icon + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: const Color(0xFFFFF3E0), + borderRadius: BorderRadius.circular(40), + ), + child: const Icon( + Icons.event_busy, + color: Color(0xFFFF9800), + size: 50, + ), + ), + const SizedBox(height: 16), + + // Title + const Text( + 'Jadwal Tidak Tersedia', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 12), + + // Message + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + decoration: BoxDecoration( + color: const Color(0xFFFFF3E0), + borderRadius: BorderRadius.circular(10), + border: Border.all(color: const Color(0xFFFFE0B2)), + ), + child: Row( + children: [ + const Icon( + Icons.info_outline, + color: Color(0xFFFF9800), + size: 24, + ), + const SizedBox(width: 12), + Expanded( + child: Text( + errorMessage, + style: const TextStyle( + fontSize: 14, + color: Color(0xFF5F4C00), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 24), + + // Button + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFFF9800), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 2, + ), + child: const Text( + 'Pilih Jadwal Lain', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + extendBodyBehindAppBar: false, + appBar: AppBar( + title: const Text( + 'Detail Booking', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + letterSpacing: 0.2, + ), + ), + backgroundColor: Colors.white, + elevation: 0, + centerTitle: true, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + automaticallyImplyLeading: false, + ), + body: NotificationListener( + onNotification: (scrollNotification) { + return false; + }, + child: SingleChildScrollView( + physics: const ClampingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Info Penjahit + Row( + children: [ + // Foto penjahit - Hilangkan background + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: widget.tailorImage != null && + widget.tailorImage!.startsWith('/storage') + ? Image.network( + ApiService.getFullImageUrl(widget.tailorImage!), + width: 40, + height: 40, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Image.asset( + 'assets/images/tailor_1.png', + width: 40, + height: 40, + fit: BoxFit.cover, + ); + }, + ) + : Image.asset( + widget.tailorImage ?? + 'assets/images/tailor_1.png', + width: 40, + height: 40, + fit: BoxFit.cover, + ), + ), + const SizedBox(width: 12), + // Nama penjahit dan lokasi + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.tailorName, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + const Text( + 'Jalan Maritai No.45', + style: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + ], + ), + ], + ), + + const SizedBox(height: 20), + + // Info Pemesanan + const Text( + 'Info Pemesanan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + + const SizedBox(height: 16), + + // Gunakan LabelText untuk label + const LabelText(text: 'Tentukan Jam Temu:'), + + // Gunakan DropdownField untuk dropdown tanggal + DropdownField( + value: _selectedDate, + onTap: _showDatePicker, + ), + + const SizedBox(height: 12), + + // Dropdown jam + DropdownField( + value: _selectedTime, + onTap: _showTimePicker, + ), + + const SizedBox(height: 16), + + // Jenis Layanan + const LabelText(text: 'Jenis Layanan:'), + + // Dropdown jenis layanan + DropdownField( + value: _selectedService, + onTap: _showServiceOptions, + ), + + const SizedBox(height: 12), + + // Kategori Pakaian + const LabelText(text: 'Kategori Pakaian:'), + + // Dropdown kategori pakaian + DropdownField( + value: _selectedCategory, + onTap: _showCategoryOptions, + ), + + const SizedBox(height: 12), + + // Metode Pembayaran + const LabelText(text: 'Metode Pembayaran:'), + + // Dropdown metode pembayaran + DropdownField( + value: _getPaymentMethodDisplayName(), + onTap: _showPaymentMethodOptions, + ), + + const SizedBox(height: 12), + + // Upload Foto - gunakan widget terpisah + ImageUploadField( + description: _imageDescription, + selectedImage: _selectedImage, + onTap: _selectImage, + ), + + const SizedBox(height: 12), + + // Detail Pesanan + const LabelText(text: 'Detail Pesanan:'), + + // Text field detail + MultilineTextField( + hintText: 'Tulis detail pesanan Anda di sini...', + controller: _notesController, + ), + + const SizedBox(height: 30), + + // Tombol Konfirmasi Booking - gunakan CustomButton + CustomButton( + text: 'Konfirmasi Booking', + onPressed: _confirmBooking, + borderRadius: 8, + ), + ], + ), + ), + ), + ), + ); + } + + // Helper method untuk mendapatkan nama tampilan metode pembayaran + String _getPaymentMethodDisplayName() { + switch (_selectedPaymentMethod) { + case 'transfer_bank': + return 'Transfer Bank'; + case 'cod': + return 'Cash on Delivery (COD)'; + default: + return 'Pilih Metode Pembayaran'; + } + } + + void _showDatePicker() async { + final date = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime.now(), + lastDate: DateTime.now().add(const Duration(days: 60)), + ); + + if (date != null) { + setState(() { + _selectedDate = "${date.day}/${date.month}/${date.year}"; + }); + } + } + + void _showTimePicker() async { + final time = await showTimePicker( + context: context, + initialTime: TimeOfDay.now(), + ); + + if (time != null) { + setState(() { + _selectedTime = + "${time.hour}:${time.minute.toString().padLeft(2, '0')}"; + }); + } + } + + void _showServiceOptions() { + showModalBottomSheet( + context: context, + builder: (context) { + return Container( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Pilih Jenis Layanan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + _buildServiceOption('Jahit Baru'), + _buildServiceOption('Perbaikan'), + ], + ), + ); + }, + ); + } + + Widget _buildServiceOption(String service) { + return ListTile( + title: Text(service), + onTap: () { + setState(() { + _selectedService = service; + }); + Navigator.pop(context); + }, + ); + } + + void _showCategoryOptions() { + showModalBottomSheet( + context: context, + builder: (context) { + return Container( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Pilih Kategori Pakaian', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + _buildCategoryOption('Atasan'), + _buildCategoryOption('Bawahan'), + _buildCategoryOption('Terusan'), + ], + ), + ); + }, + ); + } + + Widget _buildCategoryOption(String category) { + return ListTile( + title: Text(category), + onTap: () { + setState(() { + _selectedCategory = category; + }); + Navigator.pop(context); + }, + ); + } + + void _confirmBooking() async { + // Validasi input + if (_selectedDate == 'Pilih Tanggal' || + _selectedTime == 'Pilih Jam Temu' || + _selectedService == 'Pilih Jenis Layanan' || + _selectedCategory == 'Pilih Kategori') { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Harap lengkapi semua data pemesanan')), + ); + return; + } + + // Variabel untuk menyimpan BuildContext + final currentContext = context; + + // Tampilkan dialog konfirmasi + showDialog( + context: currentContext, + builder: (dialogContext) => AlertDialog( + title: const Text('Konfirmasi Booking'), + content: + const Text('Booking Anda akan dikirim ke penjahit. Lanjutkan?'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(dialogContext), + child: const Text('Batal'), + ), + TextButton( + onPressed: () async { + // Tutup dialog konfirmasi + Navigator.pop(dialogContext); + + // Variabel untuk status loading dialog + bool isLoadingShown = false; + + try { + // Tampilkan loading dialog + isLoadingShown = true; + showDialog( + context: currentContext, + barrierDismissible: false, + builder: (loadingContext) => WillPopScope( + onWillPop: () async => false, + child: const Dialog( + child: Padding( + padding: EdgeInsets.all(20.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircularProgressIndicator(), + SizedBox(width: 20), + Text("Mengirim booking..."), + ], + ), + ), + ), + ), + ); + + // Format tanggal dan waktu + final dateParts = _selectedDate.split('/'); + final formattedDate = + '${dateParts[2]}-${dateParts[1].padLeft(2, '0')}-${dateParts[0].padLeft(2, '0')}'; + + // Format waktu ke format H:i + final formattedTime = _formatTimeToHi(_selectedTime); + + // Kirim data booking ke API melalui BookingService + final result = await BookingService.createBooking( + tailorId: widget.tailorId, + appointmentDate: formattedDate, + appointmentTime: formattedTime, + serviceType: _selectedService, + category: _selectedCategory, + notes: _notesController.text, + paymentMethod: _selectedPaymentMethod, + image: _selectedImage, + ); + + // Tutup loading dialog jika masih ditampilkan + if (isLoadingShown && Navigator.canPop(currentContext)) { + Navigator.pop(currentContext); + isLoadingShown = false; + } + + if (result['success']) { + // Booking berhasil dibuat + if (currentContext.mounted) { + final data = result['data']; + final transactionCode = data['transaction_code'] ?? 'UNKNOWN'; + + // Tampilkan dialog sukses dengan kode transaksi + _showBookingSuccessDialog(transactionCode); + } + } else { + // Cek apakah error karena jadwal tidak tersedia + if (result['data'] != null && + result['data'] is Map && + result['data'].containsKey('appointment')) { + + // Tampilkan dialog jadwal tidak tersedia + if (currentContext.mounted) { + _showScheduleNotAvailableDialog(result['data']['appointment']); + } + } else { + // Tampilkan pesan error umum + if (currentContext.mounted) { + ScaffoldMessenger.of(currentContext).showSnackBar( + SnackBar( + content: + Text(result['message'] ?? 'Gagal membuat booking'), + backgroundColor: Colors.red, + ), + ); + } + } + } + } catch (e) { + // Tutup loading dialog jika masih ditampilkan + if (isLoadingShown && Navigator.canPop(currentContext)) { + Navigator.pop(currentContext); + isLoadingShown = false; + } + + // Tampilkan pesan error + if (currentContext.mounted) { + ScaffoldMessenger.of(currentContext).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + }, + child: const Text('Konfirmasi'), + ), + ], + ), + ); + } + + // Tambahkan method baru untuk memformat waktu ke format H:i + String _formatTimeToHi(String timeString) { + // Jika masih default, kembalikan waktu default yang valid + if (timeString == 'Pilih Jam Temu') { + return '09:00'; + } + + // Pemecahan string waktu + final parts = timeString.split(':'); + if (parts.length != 2) { + // Jika format tidak sesuai, kembalikan format default + return '09:00'; + } + + // Pastikan jam dan menit dalam format yang benar + final hour = int.tryParse(parts[0]) ?? 9; + final minute = int.tryParse(parts[1]) ?? 0; + + // Format ke H:i + return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}'; + } + + @override + void dispose() { + _notesController.dispose(); + super.dispose(); + } +} diff --git a/TA_android/lib/pages/costumer/home/description_page.dart b/TA_android/lib/pages/costumer/home/description_page.dart new file mode 100644 index 0000000..b623ef0 --- /dev/null +++ b/TA_android/lib/pages/costumer/home/description_page.dart @@ -0,0 +1,707 @@ +import 'package:flutter/material.dart'; +import '../../../core/models/tailor_model.dart'; +import '../../../core/models/gallery_model.dart'; +import '../../../core/services/api_service.dart'; +import 'booking_page.dart'; +import 'review_page.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +// ignore_for_file: avoid_print + + +//Halaman Detail Penjahit +class DescriptionPage extends StatefulWidget { + final TailorModel tailor; + + const DescriptionPage({ + super.key, + required this.tailor, + }); + + @override + State createState() => _DescriptionPageState(); +} + +class _DescriptionPageState extends State { + bool _isLoading = false; + late TailorModel _tailorDetail; + List _galleryItems = []; + + @override + void initState() { + super.initState(); + _tailorDetail = widget.tailor; + _loadTailorGallery(); + } + + Future _loadTailorGallery() async { + setState(() { + _isLoading = true; + }); + + try { + // Load tailor gallery saja, tidak fetch ulang detail tailor + final galleryResult = + await ApiService.getTailorGalleryById(_tailorDetail.id); + + if (galleryResult['success']) { + setState(() { + _galleryItems = galleryResult['gallery'] as List; + }); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Error: $e')), + ); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: const Text( + 'Detail Penjahit', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + letterSpacing: 0.2, + ), + ), + backgroundColor: Colors.white, + elevation: 0, + centerTitle: true, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + foregroundColor: const Color(0xFF1A2552), + leading: Container( + margin: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(8), + ), + child: IconButton( + icon: const Icon( + Icons.arrow_back_ios_new, + color: Color(0xFF1A2552), + size: 18, + ), + onPressed: () => Navigator.of(context).pop(), + splashRadius: 24, + ), + ), + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : NotificationListener( + onNotification: (scrollNotification) { + return false; + }, + child: RefreshIndicator( + onRefresh: _loadTailorGallery, + child: SingleChildScrollView( + physics: const ClampingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header dengan foto dan info penjahit + Row( + children: [ + // Foto penjahit + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: SizedBox( + width: 50, + height: 50, + child: _tailorDetail.profilePhoto != null + ? Image.network( + ApiService.getFullImageUrl( + _tailorDetail.profilePhoto!), + width: 50, + height: 50, + fit: BoxFit.cover, + errorBuilder: + (context, error, stackTrace) { + return Image.asset( + 'assets/images/tailor_default.png', + width: 50, + height: 50, + fit: BoxFit.cover, + ); + }, + ) + : Image.asset( + 'assets/images/tailor_default.png', + width: 50, + height: 50, + fit: BoxFit.cover, + ), + ), + ), + const SizedBox(width: 16), + // Nama dan rating + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _tailorDetail.name, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 4), + Row( + children: [ + const Icon( + Icons.star, + color: Colors.amber, + size: 16, + ), + const SizedBox(width: 4), + Text( + (_tailorDetail.average_rating ?? 0.0).toStringAsFixed(1), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 4), + Text( + '(${_tailorDetail.completed_orders ?? 0} ulasan)', + style: TextStyle( + fontSize: 12, + color: Colors.grey[600], + ), + ), + ], + ), + ], + ), + ], + ), + + const SizedBox(height: 24), + + // Info Pemesanan + const Text( + 'Info Pemesanan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + _tailorDetail.shopDescription ?? + 'Jahit bisa dilakukan dimana saja sesuai dengan lokasi penjahit. Penemuan ukuran juga dapat dilakukan dilokasi penjahit.', + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + + const SizedBox(height: 16), + + // Alamat + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + width: 100, + child: Text( + 'Alamat', + style: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + ), + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _tailorDetail.address ?? 'Alamat tidak tersedia', + style: const TextStyle( + fontSize: 12, + ), + ), + const SizedBox(width: 4), + if (_tailorDetail.address.isNotEmpty == true) + GestureDetector( + onTap: () => _launchMaps(_tailorDetail.latitude, _tailorDetail.longitude), + child: const Icon( + Icons.location_on, + size: 18, + color: Color(0xFF1A2552), + ), + ), + ], + ), + ), + ], + ), + + const SizedBox(height: 8), + + // Jam Kerja + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + width: 100, + child: Text( + 'Nomor HP', + style: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + ), + Expanded( + child: Row( + children: [ + Text( + _tailorDetail.phoneNumber, + style: const TextStyle( + fontSize: 12, + ), + ), + const SizedBox(width: 8), + InkWell( + onTap: () => _launchWhatsApp(_tailorDetail.phoneNumber), + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: const Color(0xFF25D366), + borderRadius: BorderRadius.circular(4), + ), + child: const FaIcon( + FontAwesomeIcons.whatsapp, + color: Colors.white, + size: 16, + ), + ), + ), + ], + ), + ), + ], + ), + + const SizedBox(height: 24), + + // Galeri Hasil Jahit + const Text( + 'Galeri Hasil Jahit', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + _galleryItems.isEmpty + ? Container( + height: 100, + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(8), + ), + alignment: Alignment.center, + child: const Text( + 'Belum ada foto di galeri', + style: TextStyle(color: Colors.grey), + ), + ) + : SizedBox( + height: 120, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: _galleryItems.length, + itemBuilder: (context, index) { + final gallery = _galleryItems[index]; + return Padding( + padding: + const EdgeInsets.only(right: 8.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: GestureDetector( + onTap: () => _showFullImage( + context, + ApiService.getFullImageUrl( + gallery.photo), + gallery.title, + gallery.description, + ), + child: Image.network( + ApiService.getFullImageUrl( + gallery.photo), + width: 100, + height: 120, + fit: BoxFit.cover, + errorBuilder: + (context, error, stackTrace) { + return Container( + width: 100, + height: 120, + color: Colors.grey[300], + child: const Icon( + Icons.image_not_supported), + ); + }, + ), + ), + ), + ); + }, + ), + ), + + const SizedBox(height: 24), + + // Spesialisasinya + const Text( + 'Spesialisasinya:', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + _tailorDetail.specializations.isNotEmpty + ? Column( + children: _tailorDetail.specializations + .map((spec) => _buildSpecialityItem( + spec is Map ? spec['name'] ?? 'Jahit' : 'Jahit')) + .toList(), + ) + : Column( + children: [ + _buildSpecialityItem('Jahit'), + _buildSpecialityItem('Kelim'), + _buildSpecialityItem('Merubah Model Pakaian'), + ], + ), + + const SizedBox(height: 20), + + // Tombol Booking + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => BookingPage( + tailorId: _tailorDetail.id, + tailorName: _tailorDetail.name, + tailorImage: _tailorDetail.profilePhoto, + ), + ), + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.symmetric(vertical: 12), + ), + child: const Text( + 'Booking', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + + // ===== TAMBAHAN: ULASAN PENGGUNA ===== + const SizedBox(height: 32), + const Text( + 'Ulasan Pengguna', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + if (_tailorDetail.ratings.isNotEmpty) + Column( + children: [ + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: _tailorDetail.ratings.length > 2 ? 2 : _tailorDetail.ratings.length, + itemBuilder: (context, index) { + final review = _tailorDetail.ratings[index]; + final customer = review.customer; + final customerName = customer?.name ?? '-'; + final customerPhoto = customer?.profilePhoto; + + return Container( + margin: const EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.06), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + if (customerPhoto != null && customerPhoto.isNotEmpty) + CircleAvatar( + radius: 20, + backgroundImage: NetworkImage( + ApiService.getFullImageUrl(customerPhoto), + ), + backgroundColor: Colors.grey[200], + ) + else + const CircleAvatar( + radius: 20, + backgroundColor: Colors.grey, + child: Icon(Icons.person, color: Colors.white, size: 20), + ), + const SizedBox(width: 12), + Text( + customerName, + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(width: 10), + const Icon(Icons.star, color: Colors.amber, size: 20), + const SizedBox(width: 2), + Text( + review.rating, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(width: 10), + Text( + _formatDate(review.createdAt), + style: TextStyle( + color: Colors.grey[600], + fontSize: 13, + ), + ), + ], + ), + const SizedBox(height: 10), + Text( + review.review, + style: const TextStyle(fontSize: 15), + ), + ], + ), + ), + ); + }, + ), + if (_tailorDetail.ratings.length > 2) + Align( + alignment: Alignment.centerRight, + child: TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ReviewPage( + reviews: _tailorDetail.ratings, + ), + ), + ); + }, + child: const Text('Lihat Semua Ulasan'), + ), + ), + ], + ) + else + const Text( + 'Belum ada ulasan dari pengguna.', + style: TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + // ===== END TAMBAHAN ===== + ], + ), + ), + ), + ), + ), + ); + } + + void _showFullImage( + BuildContext context, String imageUrl, String title, String description) { + showDialog( + context: context, + builder: (context) => Dialog( + insetPadding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + alignment: Alignment.topRight, + children: [ + ClipRRect( + borderRadius: + const BorderRadius.vertical(top: Radius.circular(8)), + child: Image.network( + imageUrl, + fit: BoxFit.cover, + width: double.infinity, + height: 300, + errorBuilder: (context, error, stackTrace) { + return Container( + width: double.infinity, + height: 300, + color: Colors.grey[300], + child: const Icon(Icons.image_not_supported, size: 50), + ); + }, + ), + ), + IconButton( + icon: const Icon(Icons.close, color: Colors.white), + onPressed: () => Navigator.pop(context), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (title.isNotEmpty) + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + if (description.isNotEmpty) ...[ + const SizedBox(height: 8), + Text( + description, + style: const TextStyle(fontSize: 14), + ), + ], + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildSpecialityItem(String text) { + return Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Row( + children: [ + Container( + width: 20, + height: 20, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.grey), + ), + child: const Center( + child: Icon( + Icons.check, + size: 14, + color: Colors.grey, + ), + ), + ), + const SizedBox(width: 8), + Text( + text, + style: const TextStyle( + fontSize: 14, + ), + ), + ], + ), + ); + } +} + +Future _launchMaps(String? latitude, String? longitude) async { + if (latitude == null || longitude == null || latitude.isEmpty || longitude.isEmpty) return; + + final mapUrl = 'https://www.google.com/maps/search/?api=1&query=$latitude,$longitude'; + + if (await canLaunch(mapUrl)) { + await launch(mapUrl); + } else { + print('Could not launch $mapUrl'); + } +} + +Future _launchWhatsApp(String phoneNumber) async { + // Remove any non-numeric characters from the phone number + String cleanNumber = phoneNumber.replaceAll(RegExp(r'[^0-9]'), ''); + + // If the number doesn't start with '+62' or '62', add it + if (!cleanNumber.startsWith('62')) { + if (cleanNumber.startsWith('0')) { + cleanNumber = '62${cleanNumber.substring(1)}'; + } else { + cleanNumber = '62$cleanNumber'; + } + } + + final whatsappUrl = 'https://wa.me/$cleanNumber'; + + if (await canLaunch(whatsappUrl)) { + await launch(whatsappUrl); + } else { + print('Could not launch WhatsApp'); + } +} + +String _formatDate(String? dateString) { + if (dateString == null || dateString.isEmpty) return '-'; + try { + final date = DateTime.parse(dateString); + return '${date.day}/${date.month}/${date.year}'; + } catch (e) { + return dateString ?? '-'; + } +} diff --git a/TA_android/lib/pages/costumer/home/home_page.dart b/TA_android/lib/pages/costumer/home/home_page.dart new file mode 100644 index 0000000..8fd3de6 --- /dev/null +++ b/TA_android/lib/pages/costumer/home/home_page.dart @@ -0,0 +1,506 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../../core/widgets/tailor_card.dart'; +import '../../../core/providers/user_provider.dart'; +import '../../../core/models/user_model.dart'; +import '../../../core/models/tailor_model.dart'; +import '../../../core/services/api_service.dart'; +import 'description_page.dart'; +import '../../../core/utils/logger.dart'; +import 'package:geolocator/geolocator.dart'; +import 'search_page.dart'; + +//Halaman Home atau Beranda Pelanggan + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + bool _isLoading = true; + List _nearbyTailors = []; + List _recommendedTailors = []; + List _userPreferred = []; + Position? _currentPosition; + + @override + void initState() { + super.initState(); + _loadData(); + } + + Future _loadData() async { + await _getCurrentLocation(); + await _loadRecommendedTailors(); + await _loadNearbyTailors(); + } + + Future _getCurrentLocation() async { + try { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + AppLogger.warning('Layanan lokasi tidak aktif'); + return; + } + + LocationPermission permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + AppLogger.warning('Izin lokasi ditolak'); + return; + } + } + + if (permission == LocationPermission.deniedForever) { + AppLogger.warning('Izin lokasi ditolak secara permanen'); + return; + } + + Position position = await Geolocator.getCurrentPosition(); + if (mounted) { + setState(() { + _currentPosition = position; + }); + } + AppLogger.debug( + 'Posisi saat ini: ${position.latitude}, ${position.longitude}'); + } catch (e) { + AppLogger.error('Error mendapatkan lokasi: $e'); + } + } + + Future _loadNearbyTailors() async { + if (_currentPosition == null) { + AppLogger.warning( + 'Tidak dapat memuat penjahit terdekat: lokasi tidak tersedia'); + if (mounted) { + setState(() { + _nearbyTailors = []; + _isLoading = false; + }); + } + return; + } + + try { + final result = await ApiService.getNearbyTailors( + latitude: _currentPosition!.latitude, + longitude: _currentPosition!.longitude, + ); + + AppLogger.debug('Nearby tailors response: $result'); + + if (mounted) { + setState(() { + if (result['success'] == true && result['tailors'] != null) { + _nearbyTailors = result['tailors']; + AppLogger.debug( + 'Berhasil memuat ${_nearbyTailors.length} penjahit terdekat'); + } else { + AppLogger.error( + 'Gagal memuat penjahit terdekat: ${result['message']}'); + _nearbyTailors = []; + } + _isLoading = false; + }); + } + } catch (e) { + AppLogger.error('Error memuat penjahit terdekat', error: e); + if (mounted) { + setState(() { + _nearbyTailors = []; + _isLoading = false; + }); + } + } + } + + Future _loadRecommendedTailors() async { + try { + final result = await ApiService.getRecommendedTailors(); + AppLogger.debug('Recommended tailors response: $result'); + + if (result['success'] == true) { + final tailors = result['tailors'] as List; + if (mounted) { + setState(() { + _recommendedTailors = tailors; + _userPreferred = result['userPreferred'] as List; + _isLoading = false; + }); + } + } else { + AppLogger.error( + 'Failed to load recommended tailors: ${result['message']}'); + if (mounted) { + setState(() { + _isLoading = false; + _recommendedTailors = []; + }); + } + } + } catch (e, stackTrace) { + AppLogger.error( + 'Error loading recommended tailors', + error: e, + stackTrace: stackTrace, + ); + if (mounted) { + setState(() { + _isLoading = false; + _recommendedTailors = []; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, userProvider, child) { + final User? user = userProvider.user; + + // Jika tidak ada data user, tampilkan loading + if (user == null) { + AppLogger.warning('User data is null in HomePage'); + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + return Scaffold( + backgroundColor: Colors.white, + extendBodyBehindAppBar: false, + appBar: AppBar( + title: Row( + children: [ + // Foto profil + Container( + width: 35, + height: 35, + margin: const EdgeInsets.only(right: 10), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey.shade300, + image: user.profilePhoto != null + ? DecorationImage( + image: NetworkImage( + ApiService.getFullImageUrl(user.profilePhoto!), + ), + fit: BoxFit.cover, + ) + : null, + ), + ), + // Nama user + Expanded( + child: Text( + 'Hi, ${user.name}', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + backgroundColor: Colors.white, + elevation: 0.5, + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : RefreshIndicator( + onRefresh: _loadData, + child: _buildHomeContent(), + ), + ); + }, + ); + } + + Widget _buildHomeContent() { + return SafeArea( + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics( + parent: ClampingScrollPhysics(), + ), + child: Container( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Banner dengan gambar dan teks "TEMUKAN PENJAHIT TERBAIK DI KOTAMU" + SizedBox( + height: 150, + child: PageView( + scrollDirection: Axis.horizontal, + children: [ + // Banner pertama + Container( + width: double.infinity, + decoration: BoxDecoration( + color: const Color(0xFFDEF1FF), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.asset( + 'assets/images/tailor_banner.png', + fit: BoxFit.cover, + ), + ), + ), + // Banner kedua + Container( + width: double.infinity, + decoration: BoxDecoration( + color: const Color(0xFFDEF1FF), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.asset( + 'assets/images/tailor_banner2.png', + fit: BoxFit.cover, + ), + ), + ), + ], + ), + ), + + const SizedBox(height: 20), + + // Search bar + TextField( + readOnly: + true, // Jadikan read-only agar berfungsi seperti button + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SearchPage(), + ), + ); + }, + decoration: InputDecoration( + hintText: 'Cari apa?', + hintStyle: const TextStyle(color: Colors.grey), + prefixIcon: const Icon(Icons.search, color: Colors.grey), + filled: true, + fillColor: Colors.white, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: Color(0xFFE0E0E0), width: 1.0), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: Color(0xFF1A2552), width: 1.5), + ), + contentPadding: const EdgeInsets.symmetric(vertical: 0), + ), + ), + + const SizedBox(height: 20), + + // Gunakan section penjahit terdekat yang telah diperbarui + _buildNearbyTailorsSection(), + + const SizedBox(height: 20), + + // Rekomendasi Penjahit + const Text( + 'Rekomendasi Penjahit', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + + const SizedBox(height: 12), + + // Daftar rekomendasi penjahit + _recommendedTailors.isEmpty + ? const Center( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 20.0), + child: Text('Tidak ada rekomendasi penjahit'), + ), + ) + : SizedBox( + height: 180, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: _recommendedTailors.length, + itemBuilder: (context, index) { + final tailor = _recommendedTailors[index]; + + return TailorCard( + name: tailor.name, + subtitle: tailor.shopDescription?.isEmpty ?? true + ? 'Penjahit profesional' + : tailor.shopDescription!, + imagePath: tailor.profilePhoto != null + ? ApiService.getFullImageUrl( + tailor.profilePhoto!) + : 'assets/images/tailor_default.png', + rating: tailor.average_rating, + reviewCount: tailor.completed_orders, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DescriptionPage( + tailor: tailor, + ), + ), + ); + }, + ); + }, + ), + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildNearbyTailorsSection() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Penjahit Terdekat + const Text( + 'Penjahit Terdekat', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + + const SizedBox(height: 12), + + // Daftar penjahit terdekat + _nearbyTailors.isEmpty + ? _buildEmptyNearbyTailors() + : _buildNearbyTailorsList(), + ], + ); + } + + Widget _buildEmptyNearbyTailors() { + return Container( + padding: const EdgeInsets.symmetric( + vertical: 20.0, + horizontal: 16.0, + ), + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + Image.asset( + 'assets/images/no_location.png', + height: 80, + width: 80, + ), + const SizedBox(height: 8), + const Text( + 'Tidak ada penjahit terdekat', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + const Text( + 'Aktifkan lokasi untuk menemukan penjahit di sekitar Anda', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + const SizedBox(height: 12), + ElevatedButton.icon( + onPressed: () async { + setState(() => _isLoading = true); + await _getCurrentLocation(); + await _loadNearbyTailors(); + }, + icon: const Icon(Icons.refresh, size: 16), + label: const Text('Coba Lagi'), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + textStyle: const TextStyle(fontSize: 12), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + ), + ), + ], + ), + ); + } + + Widget _buildNearbyTailorsList() { + return SizedBox( + height: 180, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: _nearbyTailors.length, + itemBuilder: (context, index) { + final tailor = _nearbyTailors[index]; + final distance = tailor.distance != null + ? '${tailor.distance!.toStringAsFixed(1)} km' + : 'Jarak tidak diketahui'; + + return TailorCard( + name: tailor.name, + subtitle: distance, + imagePath: tailor.profilePhoto != null + ? ApiService.getFullImageUrl(tailor.profilePhoto!) + : 'assets/images/tailor_default.png', + rating: tailor.average_rating, + reviewCount: tailor.completed_orders, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DescriptionPage( + tailor: tailor, + ), + ), + ); + }, + ); + }, + ), + ); + } + + // Helper method untuk memastikan URL lengkap + String _getFullProfilePhotoUrl(String photoUrl) { + // Jika URL sudah lengkap, kembalikan apa adanya + if (photoUrl.startsWith('http')) { + return photoUrl; + } + + // Jika tidak, tambahkan base URL + return ApiService.getFullImageUrl(photoUrl); + } +} diff --git a/TA_android/lib/pages/costumer/home/review_page.dart b/TA_android/lib/pages/costumer/home/review_page.dart new file mode 100644 index 0000000..f99a879 --- /dev/null +++ b/TA_android/lib/pages/costumer/home/review_page.dart @@ -0,0 +1,149 @@ +import 'package:flutter/material.dart'; +import '../../../core/models/review_model.dart'; +import '../../../core/services/api_service.dart'; + +class ReviewPage extends StatefulWidget { + final List reviews; + + const ReviewPage({super.key, required this.reviews}); + + @override + State createState() => _ReviewPageState(); +} + +class _ReviewPageState extends State { + int? _selectedRating; // null = semua + + List get _filteredReviews { + if (_selectedRating == null) return widget.reviews; + return widget.reviews.where((r) { + final ratingDouble = double.tryParse(r.rating) ?? 0.0; + return ratingDouble.round() == _selectedRating; + }).toList(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Semua Ulasan'), + centerTitle: true, + backgroundColor: Colors.white, + foregroundColor: const Color(0xFF1A2552), + elevation: 0, + ), + body: Container( + color: const Color(0xFFF6F7FB), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Text('Filter: ', style: TextStyle(fontWeight: FontWeight.bold)), + DropdownButton( + value: _selectedRating, + items: const [ + DropdownMenuItem(value: null, child: Text('Semua')), + DropdownMenuItem(value: 5, child: Text('5 Bintang')), + DropdownMenuItem(value: 4, child: Text('4 Bintang')), + DropdownMenuItem(value: 3, child: Text('3 Bintang')), + DropdownMenuItem(value: 2, child: Text('2 Bintang')), + DropdownMenuItem(value: 1, child: Text('1 Bintang')), + ], + onChanged: (val) => setState(() => _selectedRating = val), + ), + ], + ), + const SizedBox(height: 12), + Expanded( + child: _filteredReviews.isEmpty + ? const Center(child: Text('Belum ada ulasan.')) + : ListView.builder( + itemCount: _filteredReviews.length, + itemBuilder: (context, index) { + final review = _filteredReviews[index]; + final customer = review.customer; + final customerName = customer?.name ?? '-'; + final customerPhoto = customer?.profilePhoto; + return Container( + margin: const EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.06), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + if (customerPhoto != null && customerPhoto.isNotEmpty) + CircleAvatar( + radius: 20, + backgroundImage: NetworkImage(ApiService.getFullImageUrl(customerPhoto)), + backgroundColor: Colors.grey[200], + ) + else + const CircleAvatar( + radius: 20, + backgroundColor: Colors.grey, + child: Icon(Icons.person, color: Colors.white, size: 20), + ), + const SizedBox(width: 12), + Text( + customerName, + style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16, color: Color(0xFF1A2552)), + ), + const SizedBox(width: 10), + const Icon(Icons.star, color: Colors.amber, size: 20), + const SizedBox(width: 2), + Text( + review.rating, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + const SizedBox(width: 10), + Text( + _formatDate(review.createdAt), + style: TextStyle(color: Colors.grey[600], fontSize: 13), + ), + ], + ), + const SizedBox(height: 10), + Text( + review.review, + style: const TextStyle(fontSize: 15), + ), + ], + ), + ), + ); + }, + ), + ), + ], + ), + ), + ), + ); + } +} + +String _formatDate(String? dateString) { + if (dateString == null || dateString.isEmpty) return '-'; + try { + final date = DateTime.parse(dateString); + return '${date.day}/${date.month}/${date.year}'; + } catch (e) { + return dateString ?? '-'; + } +} \ No newline at end of file diff --git a/TA_android/lib/pages/costumer/home/search_page.dart b/TA_android/lib/pages/costumer/home/search_page.dart new file mode 100644 index 0000000..6211bb9 --- /dev/null +++ b/TA_android/lib/pages/costumer/home/search_page.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import '../../../core/models/tailor_model.dart'; +import '../../../core/services/search_service.dart'; +import '../../../core/services/api_service.dart'; +import '../../../core/utils/logger.dart'; +import '../../../core/widgets/tailor_card.dart'; +import 'description_page.dart'; + +class SearchPage extends StatefulWidget { + const SearchPage({super.key}); + + @override + State createState() => _SearchPageState(); +} + +class _SearchPageState extends State { + final TextEditingController _searchController = TextEditingController(); + final SearchService _searchService = SearchService(); + List _searchResults = []; + bool _isLoading = false; + String _errorMessage = ''; + bool _hasSearched = false; + + Future _searchTailors(String query) async { + if (!mounted) return; + + if (query.isEmpty) { + setState(() { + _searchResults = []; + _hasSearched = false; + _errorMessage = ''; + }); + return; + } + + setState(() { + _isLoading = true; + _errorMessage = ''; + }); + + try { + final results = await _searchService.searchTailors(query); + + if (!mounted) return; + + setState(() { + _searchResults = results; + _isLoading = false; + _hasSearched = true; + _errorMessage = ''; + }); + } catch (e) { + AppLogger.error('Error saat mencari penjahit', error: e); + + if (!mounted) return; + + setState(() { + _isLoading = false; + _hasSearched = true; + _searchResults = []; + _errorMessage = 'Terjadi kesalahan saat mencari penjahit'; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: const Text( + 'Cari Penjahit', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + elevation: 0.5, + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios_new, + size: 18, color: Color(0xFF1A2552)), + onPressed: () => Navigator.pop(context), + ), + ), + body: Column( + children: [ + // Search Bar + Padding( + padding: const EdgeInsets.all(16.0), + child: TextField( + controller: _searchController, + decoration: InputDecoration( + hintText: 'Cari nama penjahit...', + prefixIcon: const Icon(Icons.search), + suffixIcon: _searchController.text.isNotEmpty + ? IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + _searchController.clear(); + _searchTailors(''); + }, + ) + : null, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFFE0E0E0)), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + ), + onChanged: (value) { + Future.delayed(const Duration(milliseconds: 500), () { + if (mounted && _searchController.text == value) { + _searchTailors(value); + } + }); + }, + ), + ), + + // Search Results + Expanded( + child: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _errorMessage.isNotEmpty + ? Center( + child: Text( + _errorMessage, + style: const TextStyle(color: Colors.red), + textAlign: TextAlign.center, + ), + ) + : !_hasSearched + ? const Center( + child: Text( + 'Cari penjahit berdasarkan nama', + style: TextStyle(color: Colors.grey), + ), + ) + : _searchResults.isEmpty + ? const Center( + child: Text( + 'Tidak ada penjahit yang ditemukan', + style: TextStyle(color: Colors.grey), + ), + ) + : _buildSearchResultsGrid(), + ), + ], + ), + ); + } + + Widget _buildSearchResultsGrid() { + return Padding( + padding: const EdgeInsets.all(16.0), + child: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 0.75, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + ), + itemCount: _searchResults.length, + itemBuilder: (context, index) { + final tailor = _searchResults[index]; + return SizedBox( + height: 180, + width: 150, + child: TailorCard( + name: tailor.name, + subtitle: tailor.shopDescription?.isNotEmpty ?? false + ? tailor.shopDescription! + : tailor.address, + imagePath: tailor.profilePhoto != null + ? ApiService.getFullImageUrl(tailor.profilePhoto!) + : 'assets/images/tailor_default.png', + rating: tailor.average_rating, + reviewCount: tailor.completed_orders, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DescriptionPage( + tailor: tailor, + ), + ), + ); + }, + ), + ); + }, + ), + ); + } + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } +} diff --git a/TA_android/lib/pages/costumer/main_page.dart b/TA_android/lib/pages/costumer/main_page.dart new file mode 100644 index 0000000..9684ab7 --- /dev/null +++ b/TA_android/lib/pages/costumer/main_page.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; +import 'home/home_page.dart'; +import 'profile/profile_page.dart'; +import 'order/order_page.dart'; +import '../../core/services/api_service.dart'; +import '../../core/routes/routes.dart'; +import '../../core/utils/logger.dart'; + +class MainPage extends StatefulWidget { + const MainPage({super.key}); + + @override + State createState() => _MainPageState(); +} + +class _MainPageState extends State { + int _currentIndex = 0; + DateTime? _lastBackPressTime; + + // Daftar halaman yang akan ditampilkan dalam TabBar + final List _pages = [ + const HomePage(), + const OrderPage(), + const ProfilePage(), + ]; + + @override + void initState() { + super.initState(); + _checkAuthentication(); + } + + Future _checkAuthentication() async { + // Periksa apakah token tersedia saat halaman dimuat + final token = await ApiService.getToken(); + if (token == null) { + AppLogger.warning('Halaman utama diakses tanpa token'); + // Redirect ke login + if (mounted) { + Navigator.pushNamedAndRemoveUntil( + context, + AppRoutes.login, + (route) => false, + ); + } + } + } + + // Fungsi untuk menangani tombol back + Future _onWillPop() async { + final now = DateTime.now(); + + if (_lastBackPressTime == null || + now.difference(_lastBackPressTime!) > const Duration(seconds: 2)) { + // Update waktu terakhir tekan back + _lastBackPressTime = now; + + // Tampilkan pesan + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Tekan sekali lagi untuk keluar'), + duration: Duration(seconds: 2), + ), + ); + + // Jangan keluar dari aplikasi + return false; + } + + // Keluar dari aplikasi + return true; + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: _onWillPop, + child: Scaffold( + body: _pages[_currentIndex], // Tampilkan halaman sesuai index + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + selectedItemColor: const Color(0xFF1A2552), + unselectedItemColor: Colors.grey, + backgroundColor: Colors.white, + elevation: 8, + type: BottomNavigationBarType + .fixed, + showSelectedLabels: true, + showUnselectedLabels: true, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home_outlined), // Menggunakan versi outline + activeIcon: Icon(Icons.home), // Versi filled saat aktif + label: 'Beranda', + ), + BottomNavigationBarItem( + icon: Icon( + Icons.receipt_outlined), // Ganti dengan icon dokumen outline + activeIcon: Icon(Icons.receipt), // Versi filled saat aktif + label: 'Pesanan', + ), + BottomNavigationBarItem( + icon: Icon(Icons.person_outline), // Menggunakan versi outline + activeIcon: Icon(Icons.person), // Versi filled saat aktif + label: 'Profile', + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/pages/costumer/order/midtrans_webview_page.dart b/TA_android/lib/pages/costumer/order/midtrans_webview_page.dart new file mode 100644 index 0000000..eea7f50 --- /dev/null +++ b/TA_android/lib/pages/costumer/order/midtrans_webview_page.dart @@ -0,0 +1,241 @@ +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; +import 'dart:async'; +// ignore_for_file: avoid_print + +class MidtransWebView extends StatefulWidget { + final String url; + final Function(String)? onUrlChanged; + final Function()? onWebViewClosed; + + const MidtransWebView({ + super.key, + required this.url, + this.onUrlChanged, + this.onWebViewClosed, + }); + + @override + State createState() => _MidtransWebViewState(); +} + +class _MidtransWebViewState extends State { + late WebViewController _controller; + bool _isLoading = true; + Timer? _checkTimer; + + @override + void initState() { + super.initState(); + _setupWebView(); + // Mulai pengecekan URL secara berkala + _startUrlCheckTimer(); + } + + @override + void dispose() { + // Hentikan timer terlebih dahulu + _checkTimer?.cancel(); + + // Panggil callback menggunakan scheduleMicrotask untuk memastikan + // callback dipanggil setelah dispose selesai secara aman + if (widget.onWebViewClosed != null) { + // Simpan reference callback untuk digunakan setelah dispose + final callback = widget.onWebViewClosed; + // Jalankan callback setelah frame ini selesai + WidgetsBinding.instance.addPostFrameCallback((_) { + callback!(); + }); + } + + super.dispose(); + } + + void _startUrlCheckTimer() { + // Cek URL setiap 2 detik + _checkTimer = Timer.periodic(const Duration(seconds: 2), (timer) async { + try { + final currentUrl = await _controller.currentUrl(); + if (currentUrl != null) { + print('URL saat ini (timer check): $currentUrl'); + + // Panggil callback onUrlChanged jika ada + if (widget.onUrlChanged != null) { + widget.onUrlChanged!(currentUrl); + } + + // Auto-close untuk URL dengan indikator spesifik + _checkForAutoCloseUrl(currentUrl); + } + } catch (e) { + print('Error checking URL: $e'); + } + }); + } + + void _checkForAutoCloseUrl(String url) { + // URL yang mengindikasikan transaksi selesai dan WebView harus ditutup + final autoCloseIndicators = [ + 'transaction_status=settlement', + 'transaction_status=capture', + 'transaction_status=paid', + 'status_code=200&transaction_status=settlement', + 'example.com/?order_id=', // Domain yang tidak diharapkan tapi mungkin muncul + '/snap/v2/finish' + ]; + + for (var indicator in autoCloseIndicators) { + if (url.contains(indicator)) { + print('URL menunjukkan transaksi selesai: $url'); + _closeWebView(true); + return; + } + } + } + + void _closeWebView(bool success) { + // Tunggu sebentar sebelum menutup (memungkinkan URL untuk diproses) + // Hentikan timer terlebih dahulu untuk mencegah callback tak terduga + _checkTimer?.cancel(); + + // Tunda penutupan WebView untuk memastikan state tree tidak terkunci + Future.delayed(const Duration(milliseconds: 300), () { + if (mounted) { + Navigator.of(context).pop(success); + } + }); + } + + void _setupWebView() { + _controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..setNavigationDelegate( + NavigationDelegate( + onPageStarted: (String url) { + print('Halaman mulai dimuat: $url'); + setState(() { + _isLoading = true; + }); + + // Panggil callback onUrlChanged + if (widget.onUrlChanged != null) { + widget.onUrlChanged!(url); + } + }, + onPageFinished: (String url) { + print('Halaman selesai dimuat: $url'); + setState(() { + _isLoading = false; + }); + + // Panggil callback onUrlChanged + if (widget.onUrlChanged != null) { + widget.onUrlChanged!(url); + } + }, + onWebResourceError: (WebResourceError error) { + print('Error saat memuat halaman: ${error.description}'); + setState(() { + _isLoading = false; + }); + }, + onNavigationRequest: (NavigationRequest request) { + print('Navigasi ke: ${request.url}'); + + // Panggil callback onUrlChanged + if (widget.onUrlChanged != null) { + widget.onUrlChanged!(request.url); + } + + // Cek domain example.com (URL redirect yang mungkin menandakan transaksi selesai) + if (request.url.contains('example.com') && request.url.contains('order_id=')) { + print('Terdeteksi URL example.com dengan order_id, kemungkinan transaksi selesai'); + // Tunggu sedikit sebelum menutup WebView + Future.delayed(const Duration(milliseconds: 500), () { + _closeWebView(true); + }); + return NavigationDecision.prevent; + } + + // Navigasi seperti biasa untuk URL lainnya + return NavigationDecision.navigate; + }, + ), + ) + ..loadRequest(Uri.parse(widget.url)); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + // Konfirmasi sebelum keluar + final shouldPop = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Konfirmasi'), + content: const Text('Apakah Anda yakin ingin membatalkan pembayaran?'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('Tidak'), + ), + TextButton( + onPressed: () => Navigator.pop(context, true), + child: const Text('Ya'), + ), + ], + ), + ); + if (shouldPop == true) { + // Pastikan callback dipanggil saat user menutup WebView + if (widget.onWebViewClosed != null) { + widget.onWebViewClosed!(); + } + return true; + } + return false; + }, + child: Scaffold( + appBar: AppBar( + title: const Text('Pembayaran'), + backgroundColor: Theme.of(context).primaryColor, + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () async { + final shouldClose = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Konfirmasi'), + content: const Text('Apakah Anda yakin ingin membatalkan pembayaran?'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('Tidak'), + ), + TextButton( + onPressed: () => Navigator.pop(context, true), + child: const Text('Ya'), + ), + ], + ), + ); + if (shouldClose == true) { + Navigator.of(context).pop(false); + } + }, + ), + ), + body: Stack( + children: [ + WebViewWidget(controller: _controller), + if (_isLoading) + const Center( + child: CircularProgressIndicator(), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/TA_android/lib/pages/costumer/order/order_detail_page.dart b/TA_android/lib/pages/costumer/order/order_detail_page.dart new file mode 100644 index 0000000..3fbc95b --- /dev/null +++ b/TA_android/lib/pages/costumer/order/order_detail_page.dart @@ -0,0 +1,3099 @@ +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'dart:io'; +import 'package:flutter_rating_bar/flutter_rating_bar.dart'; +import 'package:provider/provider.dart'; +import '../../../core/controllers/booking_controller.dart'; +import 'dart:convert'; +import '../../../core/utils/url_helper.dart'; +import 'package:intl/intl.dart'; +import '../../../core/services/auth_service.dart'; +// ignore_for_file: avoid_print + +class OrderDetailPage extends StatefulWidget { + final String status; + final Map orderData; + + const OrderDetailPage({ + super.key, + required this.status, + required this.orderData, + }); + + @override + State createState() => _OrderDetailPageState(); + + // Perbaiki helper method untuk konversi status + String getApiStatus() { + switch (status) { + case 'waiting': + return 'reservasi'; + case 'confirmation': + return 'accepted'; + case 'processing': + return 'diproses'; + case 'completed': + return 'selesai'; + case 'canceled': + return 'dibatalkan'; + default: + return 'all'; // Gunakan 'all' sebagai default, bukan 'reservasi' + } + } +} + +class _OrderDetailPageState extends State { + File? _designImage; + final TextEditingController _dateController = TextEditingController(); + final TextEditingController _timeController = TextEditingController(); + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _priceController = TextEditingController(); + final TextEditingController _datePickupController = TextEditingController(); + + String _selectedService = 'Jahit Baru'; + String _selectedCategory = 'Atasan'; + String _tailorName = ''; + String _tailorImage = ''; + + final Map _selectedSizes = { + 'Panjang Depan : 50 cm': false, + 'Lingkar Pinggang : 50 cm': false, + 'Lingkar paha : 20 cm': false, + 'Lingkar Pinggul : 50 cm': false, + 'Lingkar bahu : 20 cm': false, + 'Lingkar Paha : 20 cm': false, + }; + + double _rating = 0; + final TextEditingController _reviewController = TextEditingController(); + bool _isSubmitting = false; + + @override + void initState() { + super.initState(); + + // Debug info yang lebih detail + print('DEBUG: ===== INITIALIZING ORDER DETAIL PAGE ====='); + print('DEBUG: Status: ${widget.status}'); + print('DEBUG: Order Data: ${widget.orderData}'); + print('DEBUG: Order Data Keys: ${widget.orderData.keys.toList()}'); + print('DEBUG: Order Data Values: ${widget.orderData.values.toList()}'); + + try { + // Debug untuk tailor data + print('DEBUG: Tailor Data: ${widget.orderData['tailor']}'); + print('DEBUG: Tailor Name: ${widget.orderData['tailorName']}'); + print('DEBUG: Tailor Image: ${widget.orderData['tailorImage']}'); + + // Set data from orderData dengan penanganan null yang lebih baik + _tailorName = widget.orderData['tailorName']?.toString() ?? 'Penjahit'; + _tailorImage = widget.orderData['tailorImage']?.toString() ?? ''; + + print('DEBUG: Set Tailor Name: $_tailorName'); + print('DEBUG: Set Tailor Image: $_tailorImage'); + + // Pre-fill name dari data orderan + _nameController.text = _tailorName; + + // Debug untuk price + print('DEBUG: Price Data: ${widget.orderData['price']}'); + print('DEBUG: Price Type: ${widget.orderData['price']?.runtimeType}'); + + // Set price dari data (default jika tidak ada) + _priceController.text = + (widget.orderData['price']?.toString() ?? '200.000'); + print('DEBUG: Set Price: ${_priceController.text}'); + + // Debug untuk appointment data + print( + 'DEBUG: Appointment Date Raw: ${widget.orderData['appointmentDate']}'); + print( + 'DEBUG: Appointment Time Raw: ${widget.orderData['appointmentTime']}'); + print('DEBUG: Service Type: ${widget.orderData['serviceType']}'); + print('DEBUG: Category: ${widget.orderData['category']}'); + + // Pre-fill fields for any status dengan penanganan null yang lebih baik + String? appointmentDate = widget.orderData['appointmentDate']?.toString(); + if (appointmentDate != null && appointmentDate.isNotEmpty) { + _dateController.text = _formatDate(appointmentDate); + } + + String? appointmentTime = widget.orderData['appointmentTime']?.toString(); + if (appointmentTime != null && appointmentTime.isNotEmpty) { + _timeController.text = _formatBookingTime(appointmentTime); + } + + _selectedService = + widget.orderData['serviceType']?.toString() ?? 'Jahit Baru'; + _selectedCategory = widget.orderData['category']?.toString() ?? 'Atasan'; + + print('DEBUG: Set Appointment Date: ${_dateController.text}'); + print('DEBUG: Set Appointment Time: ${_timeController.text}'); + print('DEBUG: Set Service Type: $_selectedService'); + print('DEBUG: Set Category: $_selectedCategory'); + + // Panggil _loadBookingDetails setelah widget diinisialisasi + WidgetsBinding.instance.addPostFrameCallback((_) { + print('DEBUG: Calling _loadBookingDetails in post frame callback'); + _loadBookingDetails(); + }); + } catch (e, stackTrace) { + print('ERROR: Exception in initState: $e'); + print('ERROR: Stack trace: $stackTrace'); + // Set default values jika terjadi error + _datePickupController.text = + _formatDate(DateTime.now().add(const Duration(days: 7)).toString()); + _dateController.text = ''; + _timeController.text = ''; + _selectedService = 'Jahit Baru'; + _selectedCategory = 'Atasan'; + } + } + + // Perbaiki method _formatDate untuk menangani null dan format tanggal yang tidak valid + String _formatDate(String? dateString) { + if (dateString == null || dateString.isEmpty) { + return '-'; + } + + try { + // Jika tanggal sudah dalam format lokal (misalnya "16 April 2025") + if (dateString.contains(' ') && + !dateString.contains('-') && + !dateString.contains('/')) { + return dateString; + } + + // Coba parse tanggal dari format ISO + DateTime date; + if (dateString.contains('T')) { + // Format ISO dengan timezone + date = DateTime.parse(dateString); + } else if (dateString.contains('-')) { + // Format YYYY-MM-DD + final parts = dateString.split('-'); + if (parts.length == 3) { + date = DateTime( + int.parse(parts[0]), + int.parse(parts[1]), + int.parse(parts[2]), + ); + } else { + throw const FormatException('Format tanggal tidak valid'); + } + } else { + // Coba parse format lainnya + date = DateTime.parse(dateString); + } + + final List months = [ + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember' + ]; + + String formattedDate = + '${date.day} ${months[date.month - 1]} ${date.year}'; + print('DEBUG: Formatted date: $formattedDate from $dateString'); + return formattedDate; + } catch (e) { + print('ERROR: Gagal memformat tanggal: $dateString, error: $e'); + return '-'; + } + } + + // Perbaiki method untuk format waktu booking + String _formatBookingTime(String? time) { + if (time == null || time.isEmpty) { + return '-'; + } + + try { + print('DEBUG: Formatting booking time: $time'); + + // Jika waktu adalah "05:01" atau format jam:menit sederhana + if (time.contains(':') && time.length <= 5) { + final parts = time.split(':'); + final hour = int.parse(parts[0]); + final minute = int.parse(parts[1]); + String formattedTime = + '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}'; + print('DEBUG: Formatted simple time: $formattedTime'); + return formattedTime; + } + + // Jika format sudah HH:mm atau H:mm dengan teks tambahan + if (time.contains(':')) { + final parts = time.split(':'); + if (parts.length >= 2) { + final hour = int.parse(parts[0]); + + // Ambil menit saja tanpa detik/milisecond jika ada + String minutePart = parts[1]; + if (minutePart.contains('.')) { + minutePart = minutePart.split('.')[0]; + } + if (minutePart.contains(' ')) { + minutePart = minutePart.split(' ')[0]; + } + + final minute = int.parse(minutePart); + + // Format ke 24 jam + String formattedTime = + '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}'; + print('DEBUG: Formatted complex time: $formattedTime'); + return formattedTime; + } + } + + // Coba parse sebagai full datetime jika bentuknya lengkap + if (time.contains('T') || time.contains(' ')) { + DateTime dateTime; + if (time.contains('T')) { + dateTime = DateTime.parse(time); + } else { + dateTime = DateTime.parse('2024-01-01 $time'); + } + + String formattedTime = + '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}'; + print('DEBUG: Formatted datetime time: $formattedTime'); + return formattedTime; + } + + print('DEBUG: Using original time: $time'); + return time; + } catch (e) { + print('ERROR: Gagal memformat waktu: $time, error: $e'); + return '-'; + } + } + + Future _pickImage() async { + final ImagePicker picker = ImagePicker(); + final XFile? image = await picker.pickImage(source: ImageSource.gallery); + + if (image != null) { + setState(() { + _designImage = File(image.path); + }); + } + } + + // Perbaiki method _loadBookingDetails untuk menangani null dengan lebih baik + Future _loadBookingDetails() async { + try { + print('DEBUG: ===== LOADING BOOKING DETAILS ====='); + print('DEBUG: Order Data ID: ${widget.orderData['id']}'); + print('DEBUG: Order Data Type: ${widget.orderData['id']?.runtimeType}'); + + // Pastikan orderData memiliki semua informasi yang dibutuhkan + if (widget.orderData.containsKey('id') && widget.orderData['id'] != null) { + print('DEBUG: Using existing order data'); + setState(() { + // Ambil data tanggal dan waktu dengan penanganan null yang lebih baik + final appointmentDate = widget.orderData['appointmentDate'] ?? + widget.orderData['appointment_date'] ?? ''; + final appointmentTime = widget.orderData['appointmentTime'] ?? + widget.orderData['appointment_time'] ?? ''; + + _dateController.text = appointmentDate.toString(); + _timeController.text = appointmentTime.toString(); + _nameController.text = widget.orderData['tailorName']?.toString() ?? ''; + _priceController.text = widget.orderData['price']?.toString() ?? ''; + + print('DEBUG: Set Date Controller: ${_dateController.text}'); + print('DEBUG: Set Time Controller: ${_timeController.text}'); + print('DEBUG: Set Name Controller: ${_nameController.text}'); + print('DEBUG: Set Price Controller: ${_priceController.text}'); + + // Tangani tanggal pengambilan dengan lebih baik + String? pickupDate = widget.orderData['pickupDate'] ?? widget.orderData['pickup_date']; + print('DEBUG: Pickup date from order data: $pickupDate'); + + if (pickupDate == null || pickupDate.toString().isEmpty) { + DateTime defaultDate = DateTime.now().add(const Duration(days: 7)); + _datePickupController.text = _formatDate(defaultDate.toString()); + print('DEBUG: Using default pickup date: ${_datePickupController.text}'); + } else { + _datePickupController.text = _formatDate(pickupDate.toString()); + print('DEBUG: Using provided pickup date: ${_datePickupController.text}'); + } + + // Update selected values dengan penanganan null + _selectedService = widget.orderData['serviceType']?.toString() ?? + widget.orderData['service_type']?.toString() ?? 'Jahit Baru'; + _selectedCategory = widget.orderData['category']?.toString() ?? 'Atasan'; + _tailorName = widget.orderData['tailorName']?.toString() ?? ''; + + print('DEBUG: Set Selected Service: $_selectedService'); + print('DEBUG: Set Selected Category: $_selectedCategory'); + print('DEBUG: Set Tailor Name: $_tailorName'); + + // Dapatkan foto tailor dengan penanganan null + String? tailorPhoto; + if (widget.orderData['tailor'] != null) { + print('DEBUG: Tailor object exists: ${widget.orderData['tailor']}'); + tailorPhoto = widget.orderData['tailor']['profile_photo']?.toString(); + print('DEBUG: Tailor photo from object: $tailorPhoto'); + } + _tailorImage = tailorPhoto ?? widget.orderData['tailorImage']?.toString() ?? ''; + print('DEBUG: Set Tailor Image: $_tailorImage'); + }); + return; + } + + // Fallback ke BookingController jika data tidak lengkap + print('DEBUG: Falling back to BookingController data'); + final bookingController = Provider.of(context, listen: false); + + if (bookingController.bookings.isNotEmpty) { + // Cari booking yang sesuai dengan ID + final booking = bookingController.bookings.firstWhere( + (b) => b.id == widget.orderData['id'], + orElse: () => bookingController.bookings.first, + ); + + setState(() { + _dateController.text = booking.appointmentDate ?? ''; + _timeController.text = booking.appointmentTime ?? ''; + _nameController.text = booking.getTailorName() ?? ''; + _priceController.text = booking.totalPrice ?? ''; + + // Tangani tanggal pengambilan + String? pickupDate = booking.pickupDate; + if (pickupDate == null || pickupDate.isEmpty) { + DateTime defaultDate = DateTime.now().add(const Duration(days: 7)); + _datePickupController.text = _formatDate(defaultDate.toString()); + } else { + _datePickupController.text = _formatDate(pickupDate); + } + + _selectedService = booking.serviceType ?? 'Jahit Baru'; + _selectedCategory = booking.category ?? 'Atasan'; + _tailorName = booking.getTailorName() ?? ''; + _tailorImage = booking.getTailorPhoto() ?? ''; + }); + } + } catch (e, stackTrace) { + print('ERROR: Exception during booking detail loading: $e'); + print('ERROR: Stack trace: $stackTrace'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + } + + // Tambahkan fungsi untuk melakukan submit rating + Future _submitRating(int bookingId) async { + if (_rating == 0) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Silakan berikan rating terlebih dahulu'), + backgroundColor: Colors.red, + ), + ); + } + return; + } + + // Debug untuk ID booking + print('DEBUG: Attempting to rate booking ID: $bookingId'); + + if (bookingId <= 0) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('ID Booking tidak valid'), + backgroundColor: Colors.red, + ), + ); + } + return; + } + + if (!mounted) return; + + setState(() { + _isSubmitting = true; + }); + + try { + // Periksa autentikasi terlebih dahulu + final authData = await AuthService.getAuthData(); + + if (authData == null) { + if (mounted) { + // Tampilkan dialog login jika belum login + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: const Text('Sesi Login Berakhir'), + content: const Text( + 'Sesi login Anda telah berakhir. Silakan login kembali untuk memberikan rating dan ulasan.'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + // Arahkan ke halaman login + Navigator.of(context).pushNamedAndRemoveUntil( + '/login', (route) => false); + }, + child: const Text('Login'), + ), + ], + ), + ); + } + setState(() { + _isSubmitting = false; + }); + return; + } + + final bookingController = + Provider.of(context, listen: false); + final result = await bookingController.rateBooking( + bookingId, + _rating.round(), + _reviewController.text, + ); + + if (!mounted) return; + + // Cek apakah response mengandung error autentikasi + if (result['error_type'] == 'auth_error' || + result['message']?.toString().toLowerCase().contains('unauthenticated') == true || + result['message']?.toString().toLowerCase().contains('unauthorized') == true) { + // Tampilkan dialog login jika tidak terautentikasi + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: const Text('Sesi Login Berakhir'), + content: const Text( + 'Sesi login Anda telah berakhir. Silakan login kembali untuk memberikan rating dan ulasan.'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + // Arahkan ke halaman login + Navigator.of(context).pushNamedAndRemoveUntil( + '/login', (route) => false); + }, + child: const Text('Login'), + ), + ], + ), + ); + return; + } + + // Cek apakah ada error validasi + if (result['error_type'] == 'validation_error') { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Validasi gagal. Periksa rating dan ulasan Anda.'), + backgroundColor: Colors.orange, + ), + ); + return; + } + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Berhasil memberikan rating'), + backgroundColor: Colors.green, + ), + ); + + // Tampilkan dialog sukses + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + insetPadding: const EdgeInsets.symmetric(horizontal: 50), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 24), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Check icon di dalam lingkaran hijau + Container( + width: 56, + height: 56, + decoration: BoxDecoration( + color: Colors.green.shade50, + shape: BoxShape.circle, + ), + child: Icon( + Icons.check_circle, + color: Colors.green.shade500, + size: 36, + ), + ), + const SizedBox(height: 16), + + // Judul "Rating Berhasil" + const Text( + 'Rating Berhasil', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 12), + + // Pesan terima kasih + const Text( + 'Terima kasih atas ulasan Anda.\nKami sangat menghargai\nmasukan yang diberikan!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + height: 1.4, + color: Color(0xFF6B7280), + ), + ), + const SizedBox(height: 24), + + // Tombol OK + SizedBox( + width: double.infinity, + child: TextButton( + onPressed: () { + Navigator.of(context).pop(); + Navigator.of(context).pop(); // Kembali ke halaman sebelumnya + }, + style: TextButton.styleFrom( + backgroundColor: Colors.green.shade500, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.symmetric(vertical: 12), + ), + child: const Text( + 'OK', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ), + ), + ), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Gagal memberikan rating'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isSubmitting = false; + }); + } + } + } + + @override + void dispose() { + // Pastikan controller dibersihkan + _dateController.dispose(); + _timeController.dispose(); + _nameController.dispose(); + _priceController.dispose(); + _datePickupController.dispose(); + _reviewController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + print('DEBUG: Building order detail with status: ${widget.status}'); + print('DEBUG: Order data: ${widget.orderData}'); + print('DEBUG: Is order completed? ${_isOrderCompleted()}'); + print('DEBUG: Has rating? ${_hasRating()}'); + print('DEBUG: Rating value: ${widget.orderData['rating']}'); + print('DEBUG: Review: ${widget.orderData['review']}'); + print('DEBUG: Booking ID: ${_getBookingId()}'); + + return Scaffold( + backgroundColor: Colors.grey[50], + appBar: AppBar( + title: const Text( + 'Detail Pesanan', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 2, + shadowColor: Colors.black.withOpacity(0.1), + surfaceTintColor: Colors.white, + ), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Gunakan format yang sama untuk semua status + _buildInfoCard(context), + const SizedBox(height: 12), + _buildOrderInfoCard(), + ], + ), + ), + + // Bagian status pembayaran tetap ditampilkan untuk status yang sesuai + if ((widget.status == 'processing' || + widget.status == 'completed' || + widget.status == 'canceled') && + widget.orderData['payment_status'] != 'paid' && + widget.orderData['paymentStatus'] != 'paid') + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + color: Colors.white, + child: _buildPaymentStatusSection( + widget.orderData['payment_status'] ?? + widget.orderData['paymentStatus']), + ), + + // Tampilkan tombol bayar jika pesanan selesai dan belum dibayar + // Cek juga metode pembayaran bukan COD + if (_isOrderCompleted() && + !_isPaymentPaid() && + widget.orderData['transaction_code'] != null && + widget.orderData['transaction_code'].toString().isNotEmpty && + (widget.orderData['payment_method'] ?? '').toString().toLowerCase() != 'cod' && + (widget.orderData['payment_method'] ?? '').toString().toLowerCase() != 'cash_on_delivery') + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + color: Colors.white, + child: _buildPaymentButton( + _getBookingId(), + widget.orderData['total_price']?.toString() ?? '0', + widget.orderData['transaction_code'].toString(), + ), + ), + + // Rating section untuk order yang sudah selesai + if (_isOrderCompleted()) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: _buildRatingSection(_getBookingId()), + ), + + const SizedBox(height: 24), + ], + ), + ), + ); + } + + // Update method _buildProcessingOrderDetails untuk tampilan yang lebih profesional dan lengkap + Widget _buildProcessingOrderDetails() { + final statusDetail = widget.orderData['statusDetail'] ?? ''; + final notes = widget.orderData['notes']; + final serviceType = widget.orderData['serviceType'] ?? ''; + final category = widget.orderData['category'] ?? ''; + final totalPrice = widget.orderData['total_price']?.toString() ?? '0'; + + // Data tambahan yang lebih lengkap + final transactionCode = widget.orderData['transaction_code'] ?? ''; + final paymentMethod = widget.orderData['payment_method'] ?? ''; + final paymentStatus = widget.orderData['payment_status'] ?? widget.orderData['paymentStatus'] ?? ''; + final orderStatus = widget.orderData['status']?.toString().toLowerCase() ?? ''; + final createdAt = widget.orderData['created_at'] ?? ''; + final completedAt = widget.orderData['completed_at'] ?? ''; + final measurements = widget.orderData['measurements']; + final pickupDate = widget.orderData['pickup_date'] ?? widget.orderData['pickupDate'] ?? ''; + + // Periksa apakah pesanan sudah selesai dan belum dibayar + // Juga cek apakah metode pembayaran bukan COD + final bool canPayWithMidtrans = + orderStatus == 'selesai' && + paymentStatus != 'paid' && + totalPrice != '0' && + transactionCode.isNotEmpty && + paymentMethod.toLowerCase() != 'cod' && + paymentMethod.toLowerCase() != 'cash_on_delivery'; + + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header dengan status + Row( + children: [ + const Text( + 'Detail Pesanan', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const Spacer(), + // Status badge + _buildStatusBadge(orderStatus, statusDetail) + ], + ), + const SizedBox(height: 16), + const Divider(), + + // Status detail section + _buildDetailSection('Status', + Row( + children: [ + Icon(_getStatusIcon(orderStatus), size: 18, color: _getStatusColor(orderStatus)), + const SizedBox(width: 8), + Expanded( + child: Text( + statusDetail, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: _getStatusColor(orderStatus), + ), + ), + ), + ], + ) + ), + + // Jenis layanan & kategori + _buildDetailSection('Jenis Layanan', + Row( + children: [ + Icon(Icons.design_services, size: 18, color: Colors.grey[600]), + const SizedBox(width: 8), + Text( + serviceType, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + ], + ) + ), + + _buildDetailSection('Kategori', + Row( + children: [ + Icon(Icons.category, size: 18, color: Colors.grey[600]), + const SizedBox(width: 8), + Text( + category, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + ], + ) + ), + + // Kode transaksi + if (transactionCode.isNotEmpty) + _buildDetailSection('Kode Transaksi', + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: const Color(0xFFEEF2FF), + borderRadius: BorderRadius.circular(6), + border: Border.all(color: const Color(0xFFD1DEFF)), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.receipt_long, size: 16, color: Color(0xFF3B82F6)), + const SizedBox(width: 8), + Expanded( + child: Text( + transactionCode, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF3B82F6), + ), + ), + ), + ], + ), + ) + ), + + // Metode pembayaran + if (paymentMethod.isNotEmpty) + _buildDetailSection('Metode Pembayaran', + Row( + children: [ + Icon(Icons.payment, size: 18, color: Colors.grey[600]), + const SizedBox(width: 8), + Text( + _formatPaymentMethod(paymentMethod), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + ], + ) + ), + + // Status pembayaran + _buildDetailSection('Status Pembayaran', + _buildPaymentStatusBadge(paymentStatus) + ), + + // Catatan + if (notes != null && notes.toString().isNotEmpty) + _buildDetailSection('Catatan', + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey[50], + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey[200]!), + ), + child: Text( + notes.toString(), + style: TextStyle( + fontSize: 14, + color: Colors.grey[800], + ), + ), + ) + ), + + // Tanggal pesanan + if (createdAt.isNotEmpty) + _buildDetailSection('Tanggal Pesanan', + Row( + children: [ + Icon(Icons.date_range, size: 18, color: Colors.grey[600]), + const SizedBox(width: 8), + Text( + _formatDate(createdAt), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + ], + ) + ), + + // Tanggal selesai jika sudah selesai atau dalam proses + if ((completedAt != null && completedAt.isNotEmpty) || + (widget.orderData['completion_date'] != null && widget.orderData['completion_date'].toString().isNotEmpty)) + _buildDetailSection('Tanggal Selesai', + Row( + children: [ + Icon(Icons.event_available, size: 18, color: Colors.green[600]), + const SizedBox(width: 8), + Text( + _formatDate(completedAt ?? widget.orderData['completion_date']), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.green[700], + ), + ), + ], + ) + ), + + // Tanggal pengambilan jika sudah ada + if (pickupDate.isNotEmpty) + _buildDetailSection('Tanggal Pengambilan', + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade100), + ), + child: Row( + children: [ + Icon(Icons.event_note, size: 18, color: Colors.blue[700]), + const SizedBox(width: 8), + Text( + _formatDate(pickupDate), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.blue[700], + ), + ), + ], + ), + ) + ), + + // Tampilkan total harga jika ada + if (totalPrice != '0') + _buildDetailSection('Total Harga', + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: const Color(0xFFF0FDF4), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: const Color(0xFFDCFCE7)), + ), + child: Row( + children: [ + const Icon(Icons.monetization_on, size: 18, color: Color(0xFF22C55E)), + const SizedBox(width: 8), + Text( + 'Rp ${_formatCurrency(totalPrice)}', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF22C55E), + ), + ), + ], + ), + ) + ), + + // Ukuran jika ada dan jenis perbaikan adalah jahit baru + if (measurements != null && measurements.toString().isNotEmpty && serviceType.toLowerCase() == 'jahit baru') + _buildMeasurementsSection(measurements.toString(), category), + + // Tombol bayar jika belum dibayar + if (canPayWithMidtrans) + Padding( + padding: const EdgeInsets.only(top: 24), + child: SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () => _navigateToPaymentPage( + _getBookingId(), + totalPrice, + transactionCode + ), + icon: const Icon(Icons.payment), + label: const Text('Bayar Sekarang'), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1E3A8A), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + ), + ], + ), + ); + } + + // Helper widget untuk section detail + Widget _buildDetailSection(String title, Widget content) { + return Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey[600], + ), + ), + const SizedBox(height: 6), + content, + ], + ), + ); + } + + // Helper widget untuk menampilkan ukuran + Widget _buildMeasurementsSection(String measurementsString, String category) { + Map measurementsMap = {}; + + try { + // Coba parse measurements sebagai JSON + measurementsMap = jsonDecode(measurementsString); + } catch (e) { + print('ERROR: Gagal parse measurements: $e'); + // Fallback jika parsing gagal, mencoba parse manual + measurementsString = measurementsString.replaceAll('{', '').replaceAll('}', ''); + List pairs = measurementsString.split(','); + + for (String pair in pairs) { + if (pair.contains(':')) { + List keyValue = pair.split(':'); + if (keyValue.length >= 2) { + String key = keyValue[0].trim().replaceAll('"', '').replaceAll("'", ''); + String value = keyValue[1].trim().replaceAll('"', '').replaceAll("'", ''); + measurementsMap[key] = value; + } + } + } + } + + if (measurementsMap.isEmpty) { + return const SizedBox.shrink(); + } + + return _buildDetailSection('Ukuran', + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.grey[50], + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey[200]!), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Ukuran $category', + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 12), + const Divider(), + const SizedBox(height: 8), + ...measurementsMap.entries.map((entry) { + if (entry.key == 'catatan_tambahan') return const SizedBox.shrink(); + + String displayKey = entry.key.toString() + .replaceAll('_', ' ') + .split(' ') + .map((word) => word.isEmpty ? '' : '${word[0].toUpperCase()}${word.substring(1)}') + .join(' '); + + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + displayKey, + style: TextStyle( + fontSize: 14, + color: Colors.grey[800], + ), + ), + Text( + '${entry.value} cm', + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + ], + ), + ); + }), + + // Catatan tambahan jika ada + if (measurementsMap.containsKey('catatan_tambahan') && + measurementsMap['catatan_tambahan'].toString().isNotEmpty) ...[ + const SizedBox(height: 12), + const Divider(), + const SizedBox(height: 8), + Text( + 'Catatan Tambahan:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey[800], + ), + ), + const SizedBox(height: 4), + Text( + measurementsMap['catatan_tambahan'].toString(), + style: TextStyle( + fontSize: 14, + fontStyle: FontStyle.italic, + color: Colors.grey[700], + ), + ), + ], + ], + ), + ) + ); + } + + // Helper untuk warna status + Color _getStatusColor(String status) { + switch (status.toLowerCase()) { + case 'reservasi': + return const Color(0xFF3B82F6); // Blue + case 'diproses': + return const Color(0xFFF59E0B); // Amber + case 'selesai': + return const Color(0xFF10B981); // Green + case 'dibatalkan': + return const Color(0xFFEF4444); // Red + default: + return Colors.grey; + } + } + + // Helper untuk icon status + IconData _getStatusIcon(String status) { + switch (status.toLowerCase()) { + case 'reservasi': + return Icons.event; + case 'diproses': + return Icons.engineering; + case 'selesai': + return Icons.check_circle; + case 'dibatalkan': + return Icons.cancel; + default: + return Icons.info_outline; + } + } + + // Helper untuk format currency + String _formatCurrency(String price) { + // Bersihkan price dari karakter non-numerik + String cleanPrice = price.replaceAll(RegExp(r'[^0-9.]'), ''); + + // Handle decimal point + if (cleanPrice.contains('.')) { + List parts = cleanPrice.split('.'); + cleanPrice = parts[0]; // Ambil bagian integer saja + } + + // Jika kosong, return 0 + if (cleanPrice.isEmpty) return '0'; + + // Parse ke integer + int value = int.tryParse(cleanPrice) ?? 0; + + // Format dengan separator ribuan + final formatter = NumberFormat('#,###', 'id_ID'); + return formatter.format(value); + } + + // Update widget untuk menampilkan badge status pesanan + Widget _buildStatusBadge(String status, String statusDetail) { + Color bgColor; + Color textColor; + String shortStatusText = _simplifyStatusText(statusDetail); + + switch (status.toLowerCase()) { + case 'reservasi': + bgColor = const Color(0xFFEEF2FF); + textColor = const Color(0xFF3B82F6); + break; + case 'diproses': + bgColor = const Color(0xFFFEF3C7); + textColor = const Color(0xFFD97706); + break; + case 'selesai': + bgColor = const Color(0xFFD1FAE5); + textColor = const Color(0xFF10B981); + break; + case 'dibatalkan': + bgColor = const Color(0xFFFEE2E2); + textColor = const Color(0xFFEF4444); + break; + default: + bgColor = Colors.grey.shade200; + textColor = Colors.grey.shade800; + } + + return Container( + constraints: const BoxConstraints(maxWidth: 100), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(16), + ), + child: Text( + shortStatusText, + style: TextStyle( + fontSize: 11, + color: textColor, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + ), + ); + } + + // Fungsi untuk menyederhanakan teks status + String _simplifyStatusText(String statusDetail) { + // Pemetaan status panjang ke status pendek + Map statusMap = { + 'Pesanan telah selesai': 'Selesai', + 'Pesanan sedang diproses': 'Diproses', + 'Menunggu konfirmasi': 'Menunggu', + 'Pesanan dibatalkan': 'Dibatalkan', + 'Pesanan telah dikonfirmasi': 'Dikonfirmasi', + 'Menunggu pembayaran': 'Belum Bayar', + 'Pembayaran dikonfirmasi': 'Dibayar', + 'Menunggu penjahit': 'Tunggu Penjahit', + 'Menunggu pengambilan': 'Siap Diambil', + 'Pesanan telah diambil': 'Diambil', + 'Pesanan telah dibayar': 'Dibayar', + }; + + // Cari status pendek, jika tidak ditemukan gunakan original dengan batasan karakter + return statusMap[statusDetail] ?? + (statusDetail.length > 12 ? '${statusDetail.substring(0, 12)}...' : statusDetail); + } + + // Update widget untuk menampilkan badge status pembayaran + Widget _buildPaymentStatusBadge(String? paymentStatus) { + final bool isPaid = paymentStatus?.toLowerCase() == 'paid'; + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: isPaid ? const Color(0xFFD1FAE5) : const Color(0xFFFEF3C7), + borderRadius: BorderRadius.circular(6), + border: Border.all( + color: isPaid ? const Color(0xFFA7F3D0) : const Color(0xFFFCD34D), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + isPaid ? Icons.check_circle : Icons.pending, + size: 16, + color: isPaid ? const Color(0xFF10B981) : const Color(0xFFD97706), + ), + const SizedBox(width: 6), + Text( + isPaid ? 'Lunas' : 'Belum Lunas', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + color: isPaid ? const Color(0xFF10B981) : const Color(0xFFD97706), + ), + ), + ], + ), + ); + } + + // Method untuk mengecek apakah order sudah selesai + bool _isOrderCompleted() { + return widget.status == 'completed' || + (widget.orderData['status']?.toLowerCase() == 'selesai'); + } + + // Method untuk mengecek apakah booking sudah memiliki rating + bool _hasRating() { + final dynamic ratingValue = widget.orderData['rating']; + + // Jika rating berupa objek (dari API) + if (ratingValue is Map) { + return ratingValue.containsKey('rating') && + ratingValue['rating'] != null && + ratingValue['rating'].toString() != '0'; + } + + // Jika rating berupa nilai langsung + return ratingValue != null && ratingValue != 0; + } + + // Method untuk mendapatkan ID booking + int _getBookingId() { + // Cek ID langsung + if (widget.orderData.containsKey('id') && widget.orderData['id'] != null) { + final id = widget.orderData['id']; + if (id is int && id > 0) { + return id; + } else if (id is String) { + final parsedId = int.tryParse(id); + if (parsedId != null && parsedId > 0) { + return parsedId; + } + } + } + + // Default return 0 jika tidak ada ID valid + return 0; + } + + // Method untuk format metode pembayaran + String _formatPaymentMethod(String method) { + if (method.isEmpty) return '-'; + + switch(method.toLowerCase()) { + case 'transfer_bank': + return 'Transfer Bank'; + case 'cod': + case 'cash_on_delivery': + return 'Bayar di Tempat (COD)'; + case 'cash': + return 'Tunai'; + case 'gopay': + return 'GoPay'; + case 'ovo': + return 'OVO'; + case 'dana': + return 'DANA'; + case 'qris': + return 'QRIS'; + case 'midtrans': + return 'Midtrans Payment'; + default: + // Format string dengan mengganti underscore dengan spasi dan capitalize kata pertama + final words = method.split('_'); + return words.map((word) => word.isEmpty ? '' : + '${word[0].toUpperCase()}${word.substring(1).toLowerCase()}') + .join(' '); + } + } + + // Method untuk mengecek status pembayaran + bool _isPaymentPaid() { + // Cek kedua kemungkinan field status pembayaran + final String? paymentStatus1 = widget.orderData['payment_status']?.toString().toLowerCase(); + final String? paymentStatus2 = widget.orderData['paymentStatus']?.toString().toLowerCase(); + + // Return true jika salah satu status adalah 'paid' + return paymentStatus1 == 'paid' || paymentStatus2 == 'paid'; + } + + // Method untuk navigasi ke halaman pembayaran + void _navigateToPaymentPage(int bookingId, String totalPrice, String transactionCode) { + if (bookingId <= 0) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('ID booking tidak valid'), + backgroundColor: Colors.red, + ), + ); + return; + } + + // Navigasi menggunakan named route dengan parameter + Navigator.pushNamed( + context, + '/payment', + arguments: { + 'bookingId': bookingId, + 'totalPrice': totalPrice, + 'transactionCode': transactionCode, + }, + ).then((result) { + // Refresh halaman jika pembayaran berhasil + if (result == true) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Pembayaran berhasil!'), + backgroundColor: Colors.green, + ), + ); + // Muat ulang halaman + Future.delayed(const Duration(milliseconds: 500), () { + Navigator.pop(context, true); + }); + } + }); + } + + // Method untuk tombol pembayaran + Widget _buildPaymentButton(int bookingId, String totalPrice, String transactionCode) { + return SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () => _navigateToPaymentPage(bookingId, totalPrice, transactionCode), + icon: const Icon(Icons.payment), + label: const Text('Bayar Sekarang'), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1E3A8A), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ); + } + + // Method untuk menampilkan seksi status pembayaran + Widget _buildPaymentStatusSection(String? paymentStatus) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Status Pembayaran', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + _buildPaymentStatusBadge(paymentStatus), + ], + ); + } + + // Method untuk membangun info card + Widget _buildInfoCard(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 0, vertical: 8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.04), + offset: const Offset(0, 2), + blurRadius: 8, + spreadRadius: 0, + ), + BoxShadow( + color: Colors.black.withOpacity(0.02), + offset: const Offset(0, 1), + blurRadius: 4, + spreadRadius: 0, + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Judul pesanan + Text( + '$_selectedService - $_selectedCategory', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + letterSpacing: 0.2, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 16), + + // Tailor Info + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Foto penjahit + if (_tailorImage.isNotEmpty) + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: SizedBox( + width: 70, + height: 70, + child: _buildTailorImage(_tailorImage), + ), + ) + else + Container( + width: 70, + height: 70, + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(12), + ), + child: const Icon( + Icons.person, + size: 40, + color: Colors.grey, + ), + ), + const SizedBox(width: 16), + + // Info penjahit + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: const Color(0xFF1A2552).withOpacity(0.1), + borderRadius: BorderRadius.circular(6), + ), + child: const Text( + 'Penjahit', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + ), + const SizedBox(height: 6), + Text( + _tailorName, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ], + ), + ], + ), + ), + ); + } + + // Method untuk build order info card + Widget _buildOrderInfoCard() { + final String? designPhoto = widget.orderData['designPhoto']; + final String? completionPhoto = widget.orderData['completion_photo']; + final String? completionNotes = widget.orderData['completion_notes']; + final String? completionDate = widget.orderData['completion_date']; + final String? status = widget.orderData['status']?.toString().toLowerCase(); + + // Perbaiki pengambilan tanggal dan waktu + String? appointmentDate = widget.orderData['appointmentDate']; + String? appointmentTime = widget.orderData['appointmentTime']; + + // Coba ambil dari properti alternatif jika kosong + if (appointmentDate == null || appointmentDate.isEmpty) { + appointmentDate = widget.orderData['appointment_date']; + } + if (appointmentTime == null || appointmentTime.isEmpty) { + appointmentTime = widget.orderData['appointment_time']; + } + + final bool hasAppointmentDate = + appointmentDate != null && appointmentDate.isNotEmpty; + final bool hasAppointmentTime = + appointmentTime != null && appointmentTime.isNotEmpty; + + final String formattedDate = + hasAppointmentDate ? _formatDate(appointmentDate) : 'Belum ditentukan'; + final String formattedTime = + hasAppointmentTime ? _formatBookingTime(appointmentTime) : ''; + + // Buat pesan jadwal yang informatif + String scheduleMessage; + if (hasAppointmentDate && hasAppointmentTime) { + scheduleMessage = '$formattedDate $formattedTime WIB'; + } else if (hasAppointmentTime) { + scheduleMessage = 'Waktu: $formattedTime WIB (Tanggal belum ditentukan)'; + } else if (hasAppointmentDate) { + scheduleMessage = '$formattedDate (Waktu belum ditentukan)'; + } else { + scheduleMessage = 'Jadwal belum ditentukan'; + } + + // Data tambahan yang lengkap dari _buildProcessingOrderDetails + final statusDetail = widget.orderData['statusDetail'] ?? ''; + final notes = widget.orderData['notes']; + final serviceType = widget.orderData['serviceType'] ?? 'Jahit Baru'; + final category = widget.orderData['category'] ?? 'Atasan'; + final totalPrice = widget.orderData['total_price']?.toString() ?? '0'; + final transactionCode = widget.orderData['transaction_code'] ?? ''; + final paymentMethod = widget.orderData['payment_method'] ?? ''; + final paymentStatus = widget.orderData['payment_status'] ?? widget.orderData['paymentStatus'] ?? ''; + final orderStatus = widget.orderData['status']?.toString().toLowerCase() ?? ''; + final createdAt = widget.orderData['created_at'] ?? ''; + final completedAt = widget.orderData['completed_at'] ?? ''; + final measurements = widget.orderData['measurements']; + final pickupDate = widget.orderData['pickup_date'] ?? widget.orderData['pickupDate'] ?? ''; + + // Periksa apakah pesanan sudah selesai dan belum dibayar + // Juga cek apakah metode pembayaran bukan COD + final bool canPayWithMidtrans = + orderStatus == 'selesai' && + paymentStatus != 'paid' && + totalPrice != '0' && + transactionCode.isNotEmpty && + paymentMethod.toLowerCase() != 'cod' && + paymentMethod.toLowerCase() != 'cash_on_delivery'; + + return Card( + elevation: 0, + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide(color: Colors.grey.shade200), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header dengan status dalam satu baris + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Icon(Icons.info_outline, + size: 18, color: Color(0xFF1A2552)), + const SizedBox(width: 6), + const Text( + 'Detail Pemesanan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const Spacer(), + // Status badge + _buildStatusBadge(orderStatus, statusDetail), + ], + ), + const SizedBox(height: 16), + + // Info Grid Layout + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Tanggal dan Waktu Temu dalam satu container + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.event, + size: 16, color: Colors.grey.shade600), + const SizedBox(width: 8), + Text( + 'Jadwal Temu', + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + Expanded( + child: Text( + scheduleMessage, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: hasAppointmentDate && hasAppointmentTime + ? const Color(0xFF1A2552) + : Colors.orange.shade700, + ), + ), + ), + ], + ), + ], + ), + ), + const SizedBox(height: 8), + + // Jenis Layanan + _buildInfoItem( + 'Jenis Layanan', + serviceType, + icon: Icons.category, + ), + const SizedBox(height: 8), + + // Kategori + _buildInfoItem( + 'Kategori', + category, + icon: Icons.style, + ), + const SizedBox(height: 8), + + // Kode Transaksi + if (transactionCode.isNotEmpty) ...[ + _buildInfoItem( + 'Kode Transaksi', + transactionCode, + icon: Icons.receipt_long, + ), + const SizedBox(height: 8), + ], + + // Metode Pembayaran + if (paymentMethod.isNotEmpty) ...[ + _buildInfoItem( + 'Metode Pembayaran', + _formatPaymentMethod(paymentMethod), + icon: Icons.payment, + ), + const SizedBox(height: 8), + ], + + // Status Pembayaran + if (paymentStatus.isNotEmpty) ...[ + _buildDetailSection('Status Pembayaran', + _buildPaymentStatusBadge(paymentStatus) + ), + const SizedBox(height: 8), + ], + + // Tanggal pesanan + if (createdAt.isNotEmpty) ...[ + _buildInfoItem( + 'Tanggal Pesanan', + _formatDate(createdAt), + icon: Icons.date_range, + ), + const SizedBox(height: 8), + ], + + // Tanggal selesai jika sudah selesai atau dalam proses + if ((completedAt != null && completedAt.isNotEmpty) || + (widget.orderData['completion_date'] != null && widget.orderData['completion_date'].toString().isNotEmpty)) + _buildDetailSection('Tanggal Selesai', + Row( + children: [ + Icon(Icons.event_available, size: 18, color: Colors.green[600]), + const SizedBox(width: 8), + Text( + _formatDate(completedAt ?? widget.orderData['completion_date']), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.green[700], + ), + ), + ], + ) + ), + + // Tanggal pengambilan jika sudah ada + if (pickupDate.isNotEmpty) ...[ + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade100), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.event_note, size: 16, color: Colors.blue[700]), + const SizedBox(width: 8), + Text( + 'Tanggal Pengambilan', + style: TextStyle( + fontSize: 12, + color: Colors.blue[700], + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + _formatDate(pickupDate), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.blue[700], + ), + ), + ], + ), + ), + const SizedBox(height: 8), + ], + + // Tampilkan total harga jika ada dengan rincian + if (totalPrice != '0') ...[ + _buildDetailedPriceBreakdown(totalPrice), + const SizedBox(height: 8), + ], + ], + ), + + const SizedBox(height: 12), + + // Notes dan Design Photo + if (notes != null && notes.toString().isNotEmpty) ...[ + _buildNotesSection(notes.toString()), + const SizedBox(height: 12), + ], + + if (designPhoto != null) ...[ + _buildDesignPhotoSection(designPhoto), + const SizedBox(height: 12), + ], + + // Ukuran jika ada dan jenis perbaikan adalah jahit baru + if (measurements != null && measurements.toString().isNotEmpty && serviceType.toLowerCase() == 'jahit baru') ...[ + _buildMeasurementsSection(measurements.toString(), category), + const SizedBox(height: 12), + ], + + // Tampilkan completion date untuk status diproses dan selesai + if ((status == 'diproses' || status == 'selesai') && completionDate != null) ...[ + _buildInfoItem( + 'Tanggal Selesai', + _formatDate(completionDate), + icon: Icons.event_available, + iconColor: Colors.green[600], + textColor: Colors.green[700], + ), + const SizedBox(height: 8), + ], + + // Tampilkan completion photo dan notes hanya untuk status selesai + if (status == 'selesai') ...[ + if (completionPhoto != null) ...[ + _buildCompletionPhotoSection(completionPhoto), + const SizedBox(height: 12), + ], + if (completionNotes != null && completionNotes.isNotEmpty) ...[ + _buildCompletionNotesSection(completionNotes), + const SizedBox(height: 12), + ], + ], + + // Tombol bayar jika belum dibayar dan status dalam halaman detail + if (canPayWithMidtrans && widget.status == "processing") + Padding( + padding: const EdgeInsets.only(top: 12), + child: SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () => _navigateToPaymentPage( + _getBookingId(), + totalPrice, + transactionCode + ), + icon: const Icon(Icons.payment), + label: const Text('Bayar Sekarang'), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1E3A8A), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + ), + ], + ), + ), + ); + } + + // Widget baru untuk menampilkan rincian harga dengan breakdown + Widget _buildDetailedPriceBreakdown(String totalPriceStr) { + // Parse total price string ke integer + int baseTotalPrice = int.tryParse(_cleanRupiah(totalPriceStr)) ?? 0; + + // Metode pembayaran + final String paymentMethod = (widget.orderData['payment_method'] ?? '').toString().toLowerCase(); + final bool isCod = paymentMethod == 'cod' || paymentMethod == 'cash_on_delivery'; + + // Biaya tambahan - 0 jika COD + final int paymentServiceFee = isCod ? 0 : 4000; + // final int tailorServiceFee = isCod ? 0 : 1000; + + // Hitung total akhir + final int finalTotalPrice = baseTotalPrice + paymentServiceFee; + + return Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.03), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF22C55E).withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.receipt_long, + color: Color(0xFF22C55E), + size: 18, + ), + ), + const SizedBox(width: 12), + const Text( + 'Rincian Biaya', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF22C55E), + ), + ), + const Spacer(), + // Tampilkan badge COD jika metode pembayaran COD + if (isCod) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.orange.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.orange.shade200), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.monetization_on, size: 14, color: Colors.orange.shade700), + const SizedBox(width: 4), + Text( + 'COD', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Colors.orange.shade700, + ), + ), + ], + ), + ), + ], + ), + const SizedBox(height: 16), + const Divider(height: 1), + const SizedBox(height: 16), + + // Item biaya dengan format yang lebih bagus + _buildPriceItem( + "Biaya Jahit", + _formatCurrency(baseTotalPrice.toString()), + isMain: true, + ), + + // Hanya tampilkan biaya layanan jika bukan COD + if (!isCod) ...[ + _buildPriceItem( + "Biaya Layanan Payment", + _formatCurrency(paymentServiceFee.toString()), + ), + // _buildPriceItem( + // "Biaya Layanan Tailor", + // _formatCurrency(tailorServiceFee.toString()), + // ), + ] else ...[ + // Pesan penjelasan biaya COD + Padding( + padding: const EdgeInsets.only(bottom: 12, top: 4), + child: Text( + "Tidak ada biaya layanan tambahan untuk metode COD", + style: TextStyle( + fontSize: 13, + fontStyle: FontStyle.italic, + color: Colors.grey.shade600, + ), + ), + ), + ], + + const SizedBox(height: 8), + const Divider(height: 1, color: Color(0xFFE5E7EB)), + const SizedBox(height: 8), + + // Total + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Total Pembayaran', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + Text( + 'Rp ${_formatCurrency(finalTotalPrice.toString())}', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF22C55E), + ), + ), + ], + ), + ], + ), + ); + } + + // Helper untuk menampilkan item harga + Widget _buildPriceItem(String label, String price, {bool isMain = false}) { + return Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: TextStyle( + fontSize: isMain ? 15 : 14, + fontWeight: isMain ? FontWeight.w600 : FontWeight.normal, + color: isMain ? const Color(0xFF1A2552) : Colors.grey.shade700, + ), + ), + Text( + 'Rp $price', + style: TextStyle( + fontSize: isMain ? 15 : 14, + fontWeight: isMain ? FontWeight.w600 : FontWeight.w500, + color: isMain ? const Color(0xFF1A2552) : Colors.grey.shade800, + ), + ), + ], + ), + ); + } + + // Helper untuk membersihkan format rupiah + String _cleanRupiah(String nominal) { + if (nominal.isEmpty) return '0'; + + // Tangani kasus dengan angka desimal - ambil hanya bagian sebelum titik desimal + if (nominal.contains('.')) { + nominal = nominal.split('.')[0]; + } + + // Bersihkan nominal dari karakter non-angka + String cleanNominal = nominal.replaceAll(RegExp(r'[^0-9]'), ''); + + return cleanNominal; + } + + // Helper untuk tampilan widget InfoItem dengan warna kustom + Widget _buildInfoItem(String label, String value, {IconData? icon, Color? textColor, Color? iconColor}) { + return Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 10), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (icon != null) ...[ + Icon(icon, size: 16, color: iconColor ?? Colors.grey.shade600), + const SizedBox(width: 8), + ], + // Label + SizedBox( + width: 100, // Fixed width untuk label + child: Text( + label, + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + ), + const SizedBox(width: 8), + // Value dengan expanded untuk mengambil sisa ruang + Expanded( + child: Text( + value.isEmpty ? '-' : value, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: textColor ?? const Color(0xFF1A2552), + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ); + } + + // Helper untuk _buildOrderInfoCard - Notes Section + Widget _buildNotesSection(String notes) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Catatan Pesanan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Text( + notes, + style: const TextStyle( + fontSize: 14, + color: Color(0xFF333333), + height: 1.5, + ), + ), + ), + ], + ); + } + + // Helper untuk _buildOrderInfoCard - Design Photo Section + Widget _buildDesignPhotoSection(String? photoPath) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Foto Desain', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + _buildDesignPhoto(photoPath), + ], + ); + } + + // Helper untuk tampilan foto desain + Widget _buildDesignPhoto(String? photoPath) { + if (photoPath == null || photoPath.isEmpty) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + 'Tidak ada foto desain', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + ); + } + + final String fullUrl = _getFullImageUrl(photoPath); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.photo_outlined, size: 20, color: Colors.grey), + const SizedBox(width: 8), + Flexible( + child: Text( + 'Foto desain tersedia (tap untuk memperbesar)', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + const SizedBox(height: 12), + GestureDetector( + onTap: () => _showImageDialog(context, fullUrl, 'Foto Desain'), + child: Hero( + tag: 'designPhoto$photoPath', + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: AspectRatio( + aspectRatio: 16 / 9, + child: Image.network( + fullUrl, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + height: 150, + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(8), + ), + child: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.image_not_supported, + color: Colors.grey, size: 40), + SizedBox(height: 8), + Text( + 'Gagal memuat gambar', + style: TextStyle(color: Colors.grey), + ), + ], + ), + ), + ); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Container( + height: 150, + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ), + ); + }, + ), + ), + ), + ), + ), + ), + ], + ); + } + + // Helper untuk tampilan foto tailor + Widget _buildTailorImage(String imagePath) { + // Gunakan image dari network jika path tidak kosong + if (imagePath.isNotEmpty) { + // Gunakan UrlHelper untuk mendapatkan URL yang valid + final fullUrl = UrlHelper.getValidImageUrl(imagePath); + + return ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + fullUrl, + width: 70, + height: 70, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Image.asset( + 'assets/images/avatar_default.png', + width: 70, + height: 70, + fit: BoxFit.cover, + ); + }, + ), + ); + } else { + // Gunakan asset sebagai fallback + return ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.asset( + 'assets/images/avatar_default.png', + width: 70, + height: 70, + fit: BoxFit.cover, + ), + ); + } + } + + // Helper untuk mendapatkan URL lengkap foto + String _getFullImageUrl(String? photoPath) { + if (photoPath == null || photoPath.isEmpty) return ''; + + // Gunakan UrlHelper untuk mendapatkan URL yang valid + return UrlHelper.getValidImageUrl(photoPath); + } + + // Helper untuk tampilkan gambar dalam dialog + void _showImageDialog(BuildContext context, String imageUrl, String title) { + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + backgroundColor: Colors.transparent, + insetPadding: const EdgeInsets.all(8), + child: Stack( + alignment: Alignment.center, + children: [ + // Foto dengan ukuran penuh + InteractiveViewer( + panEnabled: true, + boundaryMargin: const EdgeInsets.all(20), + minScale: 0.5, + maxScale: 4, + child: Image.network( + imageUrl, + fit: BoxFit.contain, + errorBuilder: (context, error, stackTrace) { + return Container( + color: Colors.black54, + child: const Center( + child: Text( + 'Gagal memuat gambar', + style: TextStyle(color: Colors.white), + ), + ), + ); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Container( + color: Colors.black54, + child: Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + color: Colors.white, + ), + ), + ); + }, + ), + ), + // Header dengan judul dan tombol tutup + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 8, vertical: 12), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.7), + Colors.transparent, + ], + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16), + child: Text( + title, + style: const TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + IconButton( + icon: const Icon( + Icons.close, + color: Colors.white, + size: 30, + ), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ), + ], + ), + ); + }, + ); + } + + // Method untuk _buildRatingSection + Widget _buildRatingSection(int bookingId) { + print('DEBUG: Building rating section with rating data: ${widget.orderData['rating']}'); + + // Tambahkan logging untuk melihat apakah rating data valid + if (widget.orderData['rating'] is Map) { + print('DEBUG: Rating is Map with keys: ${(widget.orderData['rating'] as Map).keys.toList()}'); + print('DEBUG: Rating value: ${widget.orderData['rating']['rating']}'); + print('DEBUG: Review content: ${widget.orderData['rating']['review']}'); + } + + return Container( + margin: const EdgeInsets.only(top: 16), + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Rating & Ulasan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + + // Info box + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Bagikan pendapat Anda tentang kualitas layanan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 4), + Text( + _isPaymentPaid() + ? 'Ulasan Anda sangat membantu penjahit untuk meningkatkan kualitas layanan' + : 'Anda perlu menyelesaikan pembayaran terlebih dahulu untuk dapat memberikan ulasan', + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade700, + ), + ), + ], + ), + ), + const SizedBox(height: 16), + + // Tampilkan form rating atau rating yang sudah ada + if (_hasRating()) + _buildFixedRating() + else if (_isPaymentPaid()) + _buildRatingForm(bookingId) + else + _buildPaymentRequiredMessage(), + ], + ), + ); + } + + // Widget untuk form rating baru + Widget _buildRatingForm(int bookingId) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Text( + 'Beri Rating: ', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + RatingBar.builder( + initialRating: _rating, + minRating: 1, + direction: Axis.horizontal, + allowHalfRating: false, + itemCount: 5, + itemSize: 24, + itemPadding: const EdgeInsets.symmetric(horizontal: 2.0), + itemBuilder: (context, _) => const Icon( + Icons.star, + color: Colors.amber, + ), + onRatingUpdate: (rating) { + setState(() { + _rating = rating; + }); + }, + ), + ], + ), + const SizedBox(height: 16), + const Text( + 'Tulis Ulasan:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + TextFormField( + controller: _reviewController, + maxLines: 3, + decoration: InputDecoration( + hintText: 'Ceritakan pengalaman Anda dengan layanan ini...', + filled: true, + fillColor: Colors.white, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Color(0xFF3D77E3)), + ), + ), + ), + const SizedBox(height: 16), + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isSubmitting ? null : () => _submitRating(bookingId), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1E3A8A), + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: _isSubmitting + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : const Text( + 'Kirim Ulasan', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ); + } + + // Widget khusus untuk menampilkan rating yang sudah ada dengan perbaikan bug + Widget _buildFixedRating() { + // Ambil data rating + dynamic ratingData = widget.orderData['rating']; + print('DEBUG: Building fixed rating with data: $ratingData'); + + // Extract rating value + double ratingValue = 0; + String reviewText = ''; + + if (ratingData is Map) { + // Handle case when rating is a Map + var ratingVal = ratingData['rating']; + if (ratingVal != null) { + if (ratingVal is int) { + ratingValue = ratingVal.toDouble(); + } else if (ratingVal is String) { + ratingValue = double.tryParse(ratingVal) ?? 0; + } else if (ratingVal is double) { + ratingValue = ratingVal; + } + } + reviewText = ratingData['review']?.toString() ?? ''; + } else { + // Handle direct rating value (less common) + if (ratingData is int) { + ratingValue = ratingData.toDouble(); + } else if (ratingData is String) { + ratingValue = double.tryParse(ratingData) ?? 0; + } else if (ratingData is double) { + ratingValue = ratingData; + } + reviewText = widget.orderData['review']?.toString() ?? ''; + } + + // Ensure we have a valid rating + int displayRating = ratingValue.round(); + print('DEBUG: Final rating display value: $displayRating'); + + // Ensure we have valid review text + if (reviewText.isEmpty) { + reviewText = 'Tidak ada ulasan'; + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Text( + 'Rating: ', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(width: 4), + Row( + children: List.generate( + 5, + (index) => Icon( + index < displayRating ? Icons.star : Icons.star_border, + color: Colors.amber, + size: 20, + ), + ), + ), + const SizedBox(width: 8), + Text( + '$displayRating/5', + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + ], + ), + const SizedBox(height: 12), + const Text( + 'Ulasan Anda:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Text( + reviewText, + style: TextStyle( + fontSize: 14, + fontStyle: reviewText == 'Tidak ada ulasan' + ? FontStyle.italic + : FontStyle.normal, + color: reviewText == 'Tidak ada ulasan' + ? Colors.grey.shade600 + : Colors.black87, + height: 1.5, + ), + ), + ), + const SizedBox(height: 12), + Center( + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 10), + decoration: BoxDecoration( + color: const Color(0xFFECFDF5), + borderRadius: BorderRadius.circular(20), + border: Border.all(color: const Color(0xFFA7F3D0)), + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.check_circle, + color: Color(0xFF059669), + size: 18, + ), + SizedBox(width: 8), + Text( + 'Terima kasih atas ulasan Anda!', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + color: Color(0xFF059669), + ), + ), + ], + ), + ), + ), + ], + ); + } + + // Helper untuk menampilkan pesan pembayaran diperlukan + Widget _buildPaymentRequiredMessage() { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFFFEF3C7), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: const Color(0xFFFCD34D)), + ), + child: const Column( + children: [ + Icon( + Icons.info_outline, + color: Color(0xFFD97706), + size: 32, + ), + SizedBox(height: 12), + Text( + 'Pembayaran Diperlukan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFFD97706), + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 8), + Text( + 'Anda perlu menyelesaikan pembayaran terlebih dahulu untuk dapat memberikan ulasan.', + style: TextStyle( + fontSize: 14, + color: Color(0xFF92400E), + height: 1.4, + ), + textAlign: TextAlign.center, + ), + // Tombol Bayar Sekarang dihapus karena sudah ada di bagian atas halaman + ], + ), + ); + } + + // Helper untuk tampilan foto penyelesaian + Widget _buildCompletionPhotoSection(String photoPath) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Foto Hasil Jahitan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + _buildCompletionPhoto(photoPath), + ], + ); + } + + // Helper untuk tampilan foto hasil jahitan + Widget _buildCompletionPhoto(String? photoPath) { + if (photoPath == null || photoPath.isEmpty) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + 'Tidak ada foto hasil jahitan', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + ); + } + + final String fullUrl = _getFullImageUrl(photoPath); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.photo_outlined, size: 20, color: Colors.grey), + const SizedBox(width: 8), + Flexible( + child: Text( + 'Foto hasil jahitan tersedia (tap untuk memperbesar)', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + const SizedBox(height: 12), + GestureDetector( + onTap: () => _showImageDialog(context, fullUrl, 'Foto Hasil Jahitan'), + child: Hero( + tag: 'completionPhoto$photoPath', + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: AspectRatio( + aspectRatio: 16 / 9, + child: Image.network( + fullUrl, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + height: 150, + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(8), + ), + child: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.image_not_supported, + color: Colors.grey, size: 40), + SizedBox(height: 8), + Text( + 'Gagal memuat gambar', + style: TextStyle(color: Colors.grey), + ), + ], + ), + ), + ); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Container( + height: 150, + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ), + ); + }, + ), + ), + ), + ), + ), + ), + ], + ); + } + + // Helper untuk tampilan catatan penyelesaian + Widget _buildCompletionNotesSection(String notes) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Catatan Penyelesaian', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Text( + notes, + style: const TextStyle( + fontSize: 14, + color: Color(0xFF333333), + height: 1.5, + ), + ), + ), + ], + ); + } +} + +// Tambahkan extension untuk mempercantik tampilan teks +extension StringExtension on String { + String capitalize() { + if (isEmpty) return this; + return "${this[0].toUpperCase()}${substring(1)}"; + } +} + diff --git a/TA_android/lib/pages/costumer/order/order_page.dart b/TA_android/lib/pages/costumer/order/order_page.dart new file mode 100644 index 0000000..23cdf68 --- /dev/null +++ b/TA_android/lib/pages/costumer/order/order_page.dart @@ -0,0 +1,1468 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:intl/intl.dart'; +import '../../../core/providers/user_provider.dart'; +import '../../../core/models/user_model.dart'; +import '../../../core/services/api_service.dart'; +import '../../../core/controllers/booking_controller.dart'; +import '../../../core/models/booking_model.dart'; +import 'order_detail_page.dart'; +// ignore_for_file: avoid_print +// import '../../../core/widgets/custom_button.dart'; + +class OrderPage extends StatefulWidget { + const OrderPage({super.key}); + + @override + State createState() => _OrderPageState(); +} + +class _OrderPageState extends State { + String _selectedFilter = 'Semua'; + final List _filters = [ + 'Semua', + 'Reservasi', + 'Diproses', + 'Selesai', + 'Dibatalkan' + ]; + bool _isDisposed = false; + + @override + void dispose() { + _isDisposed = true; + super.dispose(); + } + + @override + void initState() { + super.initState(); + // Load data booking saat halaman pertama kali dibuka + if (!_isDisposed) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + _loadBookings(); + } + }); + } + } + + // Method untuk memformat angka ke format rupiah + String _formatCurrency(dynamic price) { + if (price == null) return '0'; + + // Bersihkan price dari karakter non-numerik + String cleanPrice = price.toString().replaceAll(RegExp(r'[^0-9.]'), ''); + + // Handle decimal point + if (cleanPrice.contains('.')) { + List parts = cleanPrice.split('.'); + cleanPrice = parts[0]; // Ambil bagian integer saja + } + + // Jika kosong, return 0 + if (cleanPrice.isEmpty) return '0'; + + // Parse ke integer + int value = int.tryParse(cleanPrice) ?? 0; + + // Format dengan separator ribuan + final formatter = NumberFormat('#,###', 'id_ID'); + return formatter.format(value); + } + + Future _loadBookings() async { + if (!mounted) return; + + final bookingController = + Provider.of(context, listen: false); + try { + // Convert _selectedFilter untuk filter lokal di BookingController + String filterStatus = ''; + switch (_selectedFilter) { + case 'Semua': + filterStatus = 'Semua'; // Kosong berarti ambil semua + break; + case 'Reservasi': + filterStatus = 'Reservasi'; + break; + case 'Diproses': + filterStatus = 'Diproses'; + break; + case 'Selesai': + filterStatus = 'Selesai'; + break; + case 'Dibatalkan': + filterStatus = 'Dibatalkan'; + break; + default: + filterStatus = 'Semua'; + } + + print('DEBUG: Loading bookings with filter: $filterStatus'); + + // Muat semua data booking dan gunakan filter lokal + await bookingController.loadBookings(filterStatus); + + // Debug: tampilkan data booking setelah diload + if (!mounted) return; // Pengecekan tambahan + + if (bookingController.bookings.isNotEmpty) { + print( + 'DEBUG: First booking loaded: ${bookingController.bookings[0].id}'); + print( + 'DEBUG: Tailor name: ${bookingController.bookings[0].getTailorName()}'); + print( + 'DEBUG: Tailor in booking: ${bookingController.bookings[0].tailor}'); + } else { + print('DEBUG: No bookings loaded'); + } + } catch (e) { + if (mounted) { + print('DEBUG: Error loading bookings: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + } + + void _navigateToPaymentPage(BookingModel booking) { + // Konversi totalPrice ke integer untuk menghindari error + int totalPrice = 0; + + // Coba konversi totalPrice dari berbagai format + try { + if (booking.totalPrice != null) { + // Jika totalPrice sudah berupa string, hapus karakter non-numerik + String numericPrice = booking.totalPrice!.replaceAll(RegExp(r'[^0-9]'), ''); + if (numericPrice.isNotEmpty) { + totalPrice = int.parse(numericPrice); + } + } + } catch (e) { + print('Error converting totalPrice: $e'); + } + + print('DEBUG: Navigating to payment page with totalPrice: $totalPrice (type: ${totalPrice.runtimeType})'); + + Navigator.pushNamed( + context, + '/payment', + arguments: { + 'bookingId': booking.id, + 'transactionCode': booking.transactionCode ?? 'N/A', + 'totalPrice': totalPrice, + }, + ).then((result) { + // Refresh halaman setelah kembali dari payment page + if (result == true) { + _loadBookings(); + } + }); + } + + @override + Widget build(BuildContext context) { + return Consumer2( + builder: (context, userProvider, bookingController, child) { + final User? user = userProvider.user; + + // Jika tidak ada data user, tampilkan loading + if (user == null) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: Row( + children: [ + // Foto profil + Container( + width: 35, + height: 35, + margin: const EdgeInsets.only(right: 10), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey.shade300, + border: Border.all( + color: Colors.grey.shade200, + width: 1, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(35), + child: user.profilePhoto != null && + user.profilePhoto!.isNotEmpty + ? Image.network( + _getFullProfilePhotoUrl(user.profilePhoto!), + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon( + Icons.person, + color: Colors.white, + size: 20, + ), + ); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return const Center( + child: SizedBox( + width: 15, + height: 15, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ), + ); + }, + ) + : Image.asset( + 'assets/images/avatar_default.png', + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon( + Icons.person, + color: Colors.white, + size: 20, + ), + ); + }, + ), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Pesanan Saya', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + Text( + user.name, + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade700, + fontWeight: FontWeight.normal, + ), + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ], + ), + centerTitle: false, + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + automaticallyImplyLeading: false, + ), + body: Column( + children: [ + // Filter tabs - tampilan minimalis + Container( + height: 40, + margin: const EdgeInsets.only(bottom: 8), + child: ListView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 16), + physics: const BouncingScrollPhysics(), + children: _filters.map((filter) { + final isSelected = _selectedFilter == filter; + return GestureDetector( + onTap: () { + setState(() { + _selectedFilter = filter; + }); + _loadBookings(); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + margin: const EdgeInsets.only(right: 8), + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.transparent, + border: Border( + bottom: BorderSide( + color: isSelected + ? const Color(0xFF3D77E3) + : Colors.transparent, + width: 2, + ), + ), + ), + child: Text( + filter, + style: TextStyle( + fontSize: 14, + color: isSelected + ? const Color(0xFF3D77E3) + : Colors.grey.shade700, + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.normal, + ), + ), + ), + ); + }).toList(), + ), + ), + + // Divider tipis di bawah filter + Container( + height: 1, + color: Colors.grey.shade200, + margin: const EdgeInsets.only(bottom: 16), + ), + + // Tombol refresh + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), + child: Row( + children: [ + Text('Daftar Pesanan', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: Colors.grey.shade800)), + const Spacer(), + InkWell( + onTap: _loadBookings, + borderRadius: BorderRadius.circular(20), + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF3D77E3).withOpacity(0.1), + borderRadius: BorderRadius.circular(20), + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.refresh, + color: Color(0xFF3D77E3), size: 16), + SizedBox(width: 4), + Text( + 'Refresh', + style: TextStyle( + color: Color(0xFF3D77E3), + fontWeight: FontWeight.w500, + fontSize: 12, + ), + ), + ], + ), + ), + ) + ], + ), + ), + + // Order list + Expanded( + child: bookingController.isLoading + ? const Center(child: CircularProgressIndicator()) + : bookingController.errorMessage != null + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + bookingController.errorMessage!, + style: const TextStyle(color: Colors.red), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadBookings, + child: const Text('Coba Lagi'), + ), + ], + ), + ) + : bookingController.bookings.isEmpty + ? const Center( + child: Text('Tidak ada pesanan'), + ) + : ListView.builder( + padding: + const EdgeInsets.symmetric(horizontal: 16), + itemCount: bookingController.bookings.length, + itemBuilder: (context, index) { + final booking = + bookingController.bookings[index]; + + // Debug output + print( + 'DEBUG: Building order card for booking ${booking.id}'); + print( + 'DEBUG: Customer name: ${booking.getCustomerName()}'); + print( + 'DEBUG: Profile photo path: ${booking.getProfilePhoto()}'); + print( + 'DEBUG: Formatted date: ${booking.getFormattedDate()}'); + print( + 'DEBUG: Formatted time: ${booking.getFormattedTime()}'); + print( + 'DEBUG: Repair details: ${booking.repairDetails}'); + print( + 'DEBUG: Repair notes: ${booking.repairNotes}'); + print( + 'DEBUG: Repair photo: ${booking.repairPhoto}'); + print( + 'DEBUG: Completion notes: ${booking.completionNotes}'); + print( + 'DEBUG: Completion photo: ${booking.completionPhoto}'); + print( + 'DEBUG: Completed at: ${booking.completedAt}'); + + // Debugging detail data dari getOrderDetails + final Map orderDetails = + booking.getOrderDetails(); + print( + 'DEBUG: Full orderDetails: $orderDetails'); + + return _buildOrderCard( + orderDetails, + bookingController, + ); + }, + ), + ), + ], + ), + ); + }, + ); + } + + Widget _buildOrderCard( + Map? bookingData, BookingController controller) { + print('DEBUG: Building order card with data: $bookingData'); + + // Mendapatkan data booking yang akan ditampilkan + final int bookingId = bookingData?['id'] ?? 0; + var booking = BookingModel.fromJson(bookingData ?? {}); + final String tailorName = booking.getTailorName(); + print('DEBUG: Tailor name from booking model: $tailorName'); + + // Tambahkan kode transaksi + final String transactionCode = bookingData?['transaction_code'] ?? ''; + + // Warna status sesuai dengan status pesanan + final String status = bookingData?['status'] ?? ''; + final Color statusColor = _getStatusColor(status); + + // Tambahkan variabel hasRating berdasarkan data rating + final bool hasRating = bookingData?['rating'] != null && + (bookingData?['rating'] is num || bookingData?['rating'] is Map); + + // Debug data untuk memastikan semua field ada + print('DEBUG: Building order card for booking $bookingId'); + print('DEBUG: Display Name: $tailorName'); // Log nama yang akan ditampilkan + print('DEBUG: Status: $status'); + print('DEBUG: Payment status: ${bookingData?['payment_status']}'); + print('DEBUG: Design photo: ${bookingData?['designPhoto']}'); + print('DEBUG: Completion photo: ${bookingData?['completionPhoto']}'); + print('DEBUG: Repair notes: ${bookingData?['repair_notes']}'); + print('DEBUG: Repair photo: ${bookingData?['repair_photo']}'); + print('DEBUG: Repair details: ${bookingData?['repair_details']}'); + print('DEBUG: Completion notes: ${bookingData?['completion_notes']}'); + print('DEBUG: Completed at: ${bookingData?['completed_at']}'); + print('DEBUG: Has rating: $hasRating'); + print('DEBUG: Transaction code: $transactionCode'); + + // Format tanggal dan waktu + final String appointmentDate = bookingData?['appointmentDate'] ?? ''; + final String appointmentTime = bookingData?['appointmentTime'] ?? ''; + + print('DEBUG: Raw appointment date: $appointmentDate'); + print('DEBUG: Raw appointment time: $appointmentTime'); + + final String formattedDate = _formatDate(appointmentDate); + final String formattedTime = _formatTime(appointmentTime); + + print('DEBUG: Formatted date result: $formattedDate'); + print('DEBUG: Formatted time result: $formattedTime'); + + // Buat card yang lebih informatif dan menarik + return Card( + margin: const EdgeInsets.only(bottom: 16), + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + offset: const Offset(0, 2), + blurRadius: 6, + spreadRadius: 0, + ), + BoxShadow( + color: statusColor.withOpacity(0.05), + offset: const Offset(0, 1), + blurRadius: 5, + spreadRadius: 0, + ), + ], + ), + child: InkWell( + onTap: () { + // Navigasi ke halaman detail order + if (mounted) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => OrderDetailPage( + status: _getPageStatus( + status, bookingData?['statusDetail'] ?? ''), + orderData: { + ...bookingData ?? {}, + 'id': bookingId, + 'tailorName': tailorName, + 'tailorImage': bookingData?['tailorImage'] ?? + 'assets/images/avatar_default.png', + 'serviceType': bookingData?['serviceType'] ?? 'Jahit', + 'category': bookingData?['category'] ?? 'Pakaian', + 'status': status.toLowerCase(), + 'statusDetail': bookingData?['statusDetail'] ?? '', + 'appointmentDate': bookingData?['appointmentDate'] ?? + bookingData?['appointment_date'] ?? + '', + 'appointmentTime': bookingData?['appointmentTime'] ?? + bookingData?['appointment_time'] ?? + '10:00', + 'created_at': bookingData?['created_at'] ?? '', + 'payment_status': + bookingData?['payment_status'] ?? 'unpaid', + 'transaction_code': transactionCode, + }, + ), + ), + ).then((_) { + // Refresh data setelah kembali dari halaman detail + _loadBookings(); + }); + } + }, + borderRadius: BorderRadius.circular(12), + child: Column( + children: [ + // Header dengan foto profil penjahit, nama, dan status badge + Padding( + padding: const EdgeInsets.fromLTRB(12, 12, 12, 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Foto profil penjahit + ClipRRect( + borderRadius: BorderRadius.circular(20), + child: SizedBox( + width: 36, + height: 36, + child: _buildProfileImage(bookingData?['tailorImage'] ?? + 'assets/images/avatar_default.png'), + ), + ), + const SizedBox(width: 10), + + // Info penjahit dan ID pesanan + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + tailorName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + color: Color(0xFF1A2552), + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Text( + 'Pesanan #$bookingId', + style: TextStyle( + fontSize: 11, + color: Colors.grey.shade600, + ), + ), + ], + ), + ), + ], + ), + + // Tampilkan kode transaksi sebagai informasi terpisah jika ada + if (transactionCode.isNotEmpty) + Container( + margin: const EdgeInsets.only(top: 6), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade300), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.receipt_long, size: 14, color: Colors.grey.shade700), + const SizedBox(width: 4), + Flexible( + child: Text( + 'Kode: $transactionCode', + style: TextStyle( + fontSize: 11, + color: Colors.grey.shade700, + fontWeight: FontWeight.w500, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + + // Status badge - dipindahkan ke bawah untuk menghindari konflik layout + Container( + margin: const EdgeInsets.only(top: 6), + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: statusColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: statusColor, width: 1), + ), + child: Text( + bookingData?['statusDetail'] ?? '', + style: TextStyle( + fontSize: 11, + color: statusColor, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + + // Divider + Divider(color: Colors.grey.shade200, height: 1), + + // Order details section dengan foto dan info + Padding( + padding: const EdgeInsets.all(12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Thumbnail foto desain atau hasil + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8), + ), + child: _buildOrderImage( + bookingData?['completionPhoto'], + bookingData?['designPhoto'], + bookingData?['serviceType'] ?? 'Jahit'), + ), + ), + + const SizedBox(width: 16), + + // Order details + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Service type and category + Text( + bookingData?['serviceType'] ?? 'Jahit', + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 15, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 4), + + // Jadwal temu + Row( + children: [ + Icon(Icons.calendar_today, + size: 14, color: Colors.grey.shade600), + const SizedBox(width: 4), + Text( + formattedDate != '-' && formattedTime != '-' + ? '$formattedDate $formattedTime' + : 'Jadwal belum ditentukan', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + ), + ], + ), + + const SizedBox(height: 4), + + // Tanggal-tanggal penting sesuai status + if (status.toLowerCase() == 'reservasi') ...[ + Row( + children: [ + Icon(Icons.access_time, + size: 14, color: Colors.grey.shade600), + const SizedBox(width: 4), + Text( + 'Dibuat: ${_formatDate(bookingData?['created_at'] ?? '')}', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + ), + ], + ), + ] else if (status.toLowerCase() == 'diproses') ...[ + Row( + children: [ + Icon(Icons.check_circle_outline, + size: 14, color: Colors.grey.shade600), + const SizedBox(width: 4), + Text( + 'Diterima: ${_formatDate(bookingData?['accepted_at'] ?? '')}', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + ), + ], + ), + ] else if (status.toLowerCase() == 'selesai') ...[ + Row( + children: [ + Icon(Icons.done_all, + size: 14, color: Colors.grey.shade600), + const SizedBox(width: 4), + Text( + 'Selesai: ${_formatDate(bookingData?['completed_at'] ?? '')}', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + ), + ], + ), + if (bookingData?['pickup_date'] != null) ...[ + const SizedBox(height: 4), + Row( + children: [ + Icon(Icons.local_shipping, + size: 14, color: Colors.grey.shade600), + const SizedBox(width: 4), + Text( + 'Diambil: ${_formatDate(bookingData?['pickup_date'] ?? '')}', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + ), + ], + ), + ], + ] else if (status.toLowerCase() == 'dibatalkan') ...[ + Row( + children: [ + Icon(Icons.cancel_outlined, + size: 14, color: Colors.grey.shade600), + const SizedBox(width: 4), + Text( + 'Dibatalkan: ${_formatDate(bookingData?['rejected_at'] ?? '')}', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + ), + ], + ), + if (bookingData?['rejection_reason'] != null) ...[ + const SizedBox(height: 4), + Row( + children: [ + Icon(Icons.info_outline, + size: 14, color: Colors.red.shade400), + const SizedBox(width: 4), + Expanded( + child: Text( + 'Alasan: ${bookingData?['rejection_reason']}', + style: TextStyle( + fontSize: 13, + color: Colors.red.shade400, + fontStyle: FontStyle.italic, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ], + ], + + // Catatan pesanan jika ada + if (bookingData?['notes']?.isNotEmpty == true) ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.notes, + size: 14, color: Colors.grey.shade600), + const SizedBox(width: 4), + Expanded( + child: Text( + 'Catatan: ${bookingData?['notes']}', + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade600, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ], + + // Harga jika sudah ada + if (bookingData?['total_price'] != null) ...[ + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Harga Jahit', + style: TextStyle( + fontSize: 13, + color: Color(0xFF1A2552), + ), + ), + Text( + 'Rp ${_formatCurrency(bookingData?['total_price'])}', + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + ], + ), + + // Tambahkan total dengan biaya layanan + const SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // Cek metode pembayaran untuk label + Flexible( + child: Text( + (bookingData?['payment_method'] ?? '').toString().toLowerCase() == 'cod' || + (bookingData?['payment_method'] ?? '').toString().toLowerCase() == 'cash_on_delivery' + ? 'Total Bayar' + : 'Total dengan Biaya Layanan', + style: TextStyle( + fontSize: 11, + color: Colors.grey.shade600, + overflow: TextOverflow.ellipsis, + ), + ), + ), + const SizedBox(width: 4), + Text( + _calculateTotalWithServiceFee( + bookingData?['total_price'], + paymentMethod: bookingData?['payment_method'] ?? '' + ), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Color(0xFF22C55E), + ), + ), + ], + ), + ], + ], + ), + ), + ], + ), + ), + + // Price and review button section untuk status selesai + if (status.toLowerCase() == 'selesai') + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(12), + bottomRight: Radius.circular(12), + ), + border: Border( + top: BorderSide(color: Colors.grey.shade200, width: 1), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // Status pembayaran + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + (bookingData?['payment_status'] == 'paid' || + bookingData?['paymentStatus'] == 'paid') + ? Icons.check_circle + : Icons.pending, + size: 14, + color: (bookingData?['payment_status'] == 'paid' || + bookingData?['paymentStatus'] == 'paid') + ? Colors.green + : Colors.orange, + ), + const SizedBox(width: 4), + Text( + (bookingData?['payment_status'] == 'paid' || + bookingData?['paymentStatus'] == 'paid') + ? 'Lunas' + : 'Belum Lunas', + style: TextStyle( + fontSize: 12, + color: (bookingData?['payment_status'] == + 'paid' || + bookingData?['paymentStatus'] == 'paid') + ? Colors.green + : Colors.orange, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + + // Tombol rating - hanya tampil jika pembayaran sudah lunas + if (bookingData?['payment_status'] == 'paid' || + bookingData?['paymentStatus'] == 'paid') + ElevatedButton.icon( + onPressed: () { + print( + 'DEBUG: Button pressed with booking ID: ${bookingData?['id']}'); + + // Navigasi ke halaman detail dengan parameter rating + if (mounted) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => OrderDetailPage( + status: 'completed', + orderData: { + ...bookingData ?? {}, + 'id': bookingId, + 'tailorName': tailorName, + 'tailorImage': bookingData?[ + 'tailorImage'] ?? + 'assets/images/avatar_default.png', + 'serviceType': + bookingData?['serviceType'] ?? + 'Jahit', + 'category': + bookingData?['category'] ?? 'Pakaian', + 'status': 'selesai', + 'statusDetail': 'Pesanan Selesai', + 'rating': bookingData?['rating'], + 'review': bookingData?['review'], + 'transaction_code': transactionCode, + }, + ), + ), + ).then((_) { + _loadBookings(); + }); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: hasRating + ? Colors.green + : const Color(0xFF1E3A8A), + foregroundColor: Colors.white, + elevation: 0, + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 6), + minimumSize: const Size(0, 0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + icon: Icon( + hasRating ? Icons.star : Icons.star_border, + size: 14, + ), + label: Text( + hasRating ? 'Lihat Ulasan' : 'Beri Ulasan', + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + ), + ), + ), + + // Tambahkan tombol bayar untuk status selesai yang belum lunas + if (status.toLowerCase() == 'selesai' && + bookingData?['payment_status'] != 'paid' && + bookingData?['paymentStatus'] != 'paid' && + transactionCode.isNotEmpty) ...[ + + // Cek metode pembayaran + if ((bookingData?['payment_method'] ?? '').toString().toLowerCase() != 'cod' && + (bookingData?['payment_method'] ?? '').toString().toLowerCase() != 'cash_on_delivery') ...[ + const SizedBox(width: 4), + GestureDetector( + onTap: () { + // Tampilkan dialog konfirmasi pembayaran + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Konfirmasi Pembayaran'), + content: const Text('Lanjutkan ke halaman pembayaran?'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Batal'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); // Tutup dialog + + // Navigasi ke halaman pembayaran + _navigateToPaymentPage(booking); + }, + child: const Text('Bayar', style: TextStyle(color: Colors.blue)), + ), + ], + ), + ); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + decoration: BoxDecoration( + color: Colors.blue.shade100, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.payment, size: 12, color: Colors.blue.shade800), + const SizedBox(width: 2), + Text( + 'Bayar', + style: TextStyle( + fontSize: 11, + color: Colors.blue.shade800, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + ] else ...[ + // Jika COD, tampilkan indikator metode pembayaran + const SizedBox(width: 4), + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + decoration: BoxDecoration( + color: Colors.green.shade100, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.green), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.monetization_on, size: 12, color: Colors.green.shade800), + const SizedBox(width: 2), + Text( + 'COD', + style: TextStyle( + fontSize: 11, + color: Colors.green.shade800, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ], + ], + ), + ), + ], + ), + ), + ), + ); + } + + // Metode baru untuk membangun thumbnail gambar pesanan (completion photo atau design photo) + Widget _buildOrderImage( + String? completionPhoto, String? designPhoto, String service) { + print('DEBUG: Building order image with:'); + print('DEBUG: Completion photo: $completionPhoto'); + print('DEBUG: Design photo: $designPhoto'); + + // Pilih foto yang akan ditampilkan (prioritaskan completion photo) + String? selectedPhoto = completionPhoto?.isNotEmpty == true + ? completionPhoto + : designPhoto?.isNotEmpty == true + ? designPhoto + : null; + + if (selectedPhoto == null) { + return _buildDefaultImage(service); + } + + // Gunakan FutureBuilder untuk memperbaiki URL secara asinkron + return FutureBuilder( + future: ApiService.fixDesignPhotoUrl(selectedPhoto), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center( + child: SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator(strokeWidth: 2)), + ); + } + + // Jika berhasil mendapatkan URL yang valid + if (snapshot.hasData && snapshot.data!.isNotEmpty) { + String fixedUrl = snapshot.data!; + print('DEBUG: Fixed image URL: $fixedUrl'); + + return Image.network( + fixedUrl, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print('DEBUG: Error loading fixed image: $error'); + return _buildDefaultImage(service); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + strokeWidth: 2, + ), + ); + }, + ); + } + + // Jika gagal mendapatkan URL, gunakan image default + return _buildDefaultImage(service); + }, + ); + } + + // Widget default dengan ikon berdasarkan jenis layanan + Widget _buildDefaultImage(String service) { + return Container( + color: Colors.grey.shade100, + child: Center( + child: Icon( + service.toLowerCase().contains('perbaikan') + ? Icons.construction + : Icons.design_services, + color: Colors.grey.shade400, + size: 32, + ), + ), + ); + } + + // Metode baru untuk membangun widget gambar profil + Widget _buildProfileImage(String imagePath) { + print('DEBUG: Building profile image: $imagePath'); + + if (imagePath.isEmpty || imagePath == 'assets/images/avatar_default.png') { + return Image.asset( + 'assets/images/avatar_default.png', + fit: BoxFit.cover, + ); + } + + String fullUrl = _getFullProfilePhotoUrl(imagePath); + print('DEBUG: Full image URL: $fullUrl'); + + return Image.network( + fullUrl, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print('DEBUG: Error loading image from URL: $error'); + return Image.asset( + 'assets/images/avatar_default.png', + fit: BoxFit.cover, + ); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + strokeWidth: 2, + ), + ); + }, + ); + } + + // Helper method untuk memastikan URL lengkap + String _getFullProfilePhotoUrl(String photoUrl) { + // Jika URL sudah lengkap, kembalikan apa adanya + if (photoUrl.startsWith('http')) { + return photoUrl; + } + + // Jika tidak, tambahkan base URL + return ApiService.getFullImageUrl(photoUrl); + } + + // Metode helper untuk memformat tanggal + String _formatDate(String? dateString) { + try { + print('DEBUG: Formatting date input: $dateString'); + if (dateString == null || dateString.isEmpty) { + print('DEBUG: Date string is null or empty'); + return 'Belum ditentukan'; + } + + // Jika dateString sudah dalam format yang diharapkan (seperti "26 April 2025"), + // kembalikan langsung + if (dateString.contains(' ') && + !dateString.contains('-') && + !dateString.contains('T')) { + print('DEBUG: Date string already formatted: $dateString'); + return dateString; + } + + // Coba parse tanggal dari format ISO + DateTime date; + if (dateString.contains('T')) { + // Format ISO dengan timezone + date = DateTime.parse(dateString); + print('DEBUG: Parsed ISO date with timezone: $date'); + } else if (dateString.contains('-')) { + // Format YYYY-MM-DD + final parts = dateString.split('-'); + if (parts.length == 3) { + date = DateTime( + int.parse(parts[0]), + int.parse(parts[1]), + int.parse(parts[2]), + ); + print('DEBUG: Parsed simple date: $date'); + } else { + print('ERROR: Invalid date parts length: ${parts.length}'); + return 'Format tanggal tidak valid'; + } + } else { + // Format tidak dikenal + print('ERROR: Unknown date format: $dateString'); + return 'Format tanggal tidak valid'; + } + + // Format ke bahasa Indonesia + List months = [ + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember' + ]; + + String formattedDate = + '${date.day} ${months[date.month - 1]} ${date.year}'; + print('DEBUG: Successfully formatted date: $formattedDate'); + return formattedDate; + } catch (e, stackTrace) { + print('ERROR: Exception in _formatDate: $e'); + print('ERROR: Stack trace: $stackTrace'); + print('ERROR: Original date string: $dateString'); + return 'Format tanggal tidak valid'; + } + } + + // Metode helper untuk format waktu + String _formatTime(String? time) { + try { + print('DEBUG: Formatting time input: $time'); + if (time == null || time.isEmpty) { + print('DEBUG: Time string is null or empty'); + return 'Belum ditentukan'; + } + + // Jika format waktu sudah HH:mm, tambahkan WIB + if (time.length <= 5 && time.contains(':')) { + final parts = time.split(':'); + if (parts.length == 2) { + final hour = int.parse(parts[0]); + final minute = int.parse(parts[1]); + String formattedTime = + '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')} WIB'; + print('DEBUG: Successfully formatted time: $formattedTime'); + return formattedTime; + } + } + + // Jika ada detik atau timezone, ambil hanya jam dan menit + if (time.contains(':')) { + final parts = time.split(':'); + if (parts.length >= 2) { + final hour = int.parse(parts[0]); + String minutePart = parts[1]; + if (minutePart.contains('.')) { + minutePart = minutePart.split('.')[0]; + } + if (minutePart.contains(' ')) { + minutePart = minutePart.split(' ')[0]; + } + final minute = int.parse(minutePart); + String formattedTime = + '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')} WIB'; + print('DEBUG: Successfully formatted time: $formattedTime'); + return formattedTime; + } + } + + print('DEBUG: Using original time format: $time WIB'); + return '$time WIB'; + } catch (e, stackTrace) { + print('ERROR: Exception in _formatTime: $e'); + print('ERROR: Stack trace: $stackTrace'); + print('ERROR: Original time string: $time'); + return 'Format waktu tidak valid'; + } + } + + // Helper untuk mendapatkan status halaman berdasarkan status pesanan + String _getPageStatus(String status, String statusDetail) { + switch (status.toLowerCase()) { + case 'reservasi': + return statusDetail.contains('Dikonfirmasi') + ? 'confirmation' + : 'waiting'; + case 'diproses': + return 'processing'; + case 'selesai': + return 'completed'; + case 'dibatalkan': + return 'canceled'; + default: + return 'waiting'; + } + } + + Color _getStatusColor(String status) { + switch (status.toLowerCase()) { + case 'reservasi': + return const Color(0xFF3D77E3); // Biru + case 'diproses': + return const Color(0xFFFF9800); // Orange + case 'selesai': + return const Color(0xFF1E3A8A); // Indigo + case 'dibatalkan': + return const Color(0xFFE53935); // Merah + default: + return Colors.grey; + } + } + + // Tambahkan method untuk menghitung total dengan biaya layanan + String _calculateTotalWithServiceFee(dynamic basePrice, {String? paymentMethod}) { + try { + // Parse harga dasar + String cleanPrice = basePrice.toString().replaceAll(RegExp(r'[^0-9.]'), ''); + + // Handle decimal point + if (cleanPrice.contains('.')) { + List parts = cleanPrice.split('.'); + cleanPrice = parts[0]; // Ambil bagian integer saja + } + + // Parse ke integer + int parsedPrice = int.tryParse(cleanPrice) ?? 0; + + // Cek apakah metode pembayaran adalah COD + bool isCod = paymentMethod != null && + (paymentMethod.toLowerCase() == 'cod' || + paymentMethod.toLowerCase() == 'cash_on_delivery'); + + // Tambahkan biaya layanan - 0 jika COD + final int paymentServiceFee = isCod ? 0 : 4000; + // final int tailorServiceFee = isCod ? 0 : 1000; + int totalWithFees = parsedPrice + paymentServiceFee; + + // Format total + final formatter = NumberFormat('#,###', 'id_ID'); + return 'Rp ${formatter.format(totalWithFees)}'; + } catch (e) { + print('ERROR: Gagal menghitung total dengan biaya layanan: $e'); + return 'Rp 0'; + } + } +} diff --git a/TA_android/lib/pages/costumer/order/payment_page.dart b/TA_android/lib/pages/costumer/order/payment_page.dart new file mode 100644 index 0000000..680b671 --- /dev/null +++ b/TA_android/lib/pages/costumer/order/payment_page.dart @@ -0,0 +1,853 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../../core/controllers/midtrans_controller.dart'; +import '../../../core/services/midtrans_service.dart'; +import 'package:flutter/services.dart'; +import 'dart:async'; +import 'package:intl/intl.dart'; +// ignore_for_file: avoid_print + +class PaymentPage extends StatefulWidget { + final int bookingId; + final String transactionCode; + final dynamic totalPrice; + + const PaymentPage({ + super.key, + required this.bookingId, + required this.transactionCode, + required this.totalPrice, + }); + + @override + State createState() => _PaymentPageState(); +} + +class _PaymentPageState extends State { + bool _isInitialized = false; + bool _isLoading = false; + late MidtransController _midtransController; + late int _bookingId; + late int _numericTotalPrice; + final List _statusTimers = []; + bool _isCheckingStatus = false; + + @override + void initState() { + super.initState(); + _bookingId = widget.bookingId; + _numericTotalPrice = _parseTotalPrice(widget.totalPrice); + _initPayment(); + } + + int _parseTotalPrice(dynamic price) { + print('DEBUG: Parsing price value (original): $price'); + print('DEBUG: Price type: ${price.runtimeType}'); + + if (price is int) { + print('DEBUG: Price is int: $price'); + return price; + } + + if (price is double) { + print('DEBUG: Price is double: $price'); + return price.toInt(); + } + + if (price is String) { + try { + // Hapus semua karakter non-angka + String cleanPrice = price.replaceAll(RegExp(r'[^0-9]'), ''); + print('DEBUG: Cleaned price string: $cleanPrice'); + + // Konversi ke integer + int numericPrice = int.parse(cleanPrice); + print('DEBUG: Parsed numeric price: $numericPrice'); + return numericPrice; + } catch (e) { + print('ERROR: Gagal parsing harga: $e'); + return 0; + } + } + + print('WARNING: Tipe harga tidak dikenali: ${price.runtimeType}'); + return 0; + } + + void _initPayment() { + setState(() { + _isInitialized = false; + }); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + _midtransController = Provider.of(context, listen: false); + + // Reset controller untuk memastikan state bersih + _midtransController.reset(); + + // Inisiasi pembayaran + await _openPaymentPage(); + + if (mounted) { + if (_midtransController.isPaymentInitiated) { + setState(() { + _isInitialized = true; + }); + + // Mulai pengecekan status pembayaran secara periodik + _startPaymentStatusCheck(); + } else { + _showErrorSnackBar(_midtransController.errorMessage); + + // Kembali setelah error + Future.delayed(const Duration(seconds: 2), () { + if (mounted) { + Navigator.of(context).pop(); + } + }); + } + } + }); + } + + Future _openPaymentPage() async { + try { + setState(() { + _isLoading = true; + }); + + final result = await _midtransController.initiatePayment(_bookingId); + + if (result['success'] == true) { + print('URL pembayaran siap: ${_midtransController.redirectUrl}'); + + // Inisialisasi selesai + setState(() { + _isLoading = false; + }); + + if (_midtransController.redirectUrl.isNotEmpty) { + // Buka halaman pembayaran dengan WebView dan perluas cakupan pengecekan + print('Membuka halaman WebView...'); + + // Mulai pemeriksaan status sebelum membuka WebView + _startPaymentStatusCheck(); + + // Buka halaman pembayaran + await _midtransController.openPaymentPage(context); + + // Setelah WebView ditutup, periksa status + if (mounted) { + // Pastikan pembayaran statusnya diperiksa + final statusResult = await _midtransController.checkPaymentStatus(_bookingId); + + // Cek apakah pembayaran berhasil + if (statusResult['success'] == true && + (_midtransController.paymentStatus == 'settlement' || + _midtransController.paymentStatus == 'capture' || + _midtransController.paymentStatus == 'paid')) { + // Pembayaran berhasil, tampilkan dialog dan kembali + _showPaymentSuccessDialog(); + } + } + } else { + _showErrorSnackBar('URL pembayaran tidak tersedia'); + } + } else { + setState(() { + _isLoading = false; + }); + _showErrorSnackBar(result['message'] ?? 'Gagal menginisiasi pembayaran'); + } + } catch (e) { + setState(() { + _isLoading = false; + }); + _showErrorSnackBar('Terjadi kesalahan: $e'); + print('Error saat membuka halaman pembayaran: $e'); + } + } + + void _showErrorSnackBar(String message) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(message), + backgroundColor: Colors.red, + ), + ); + } + } + + // Dialog pembayaran berhasil + void _showPaymentSuccessDialog() { + if (!mounted) return; + + // Mencegah dialog ditampilkan berulang kali + if (ModalRoute.of(context)?.isCurrent != true) { + print('Halaman tidak aktif, tidak menampilkan dialog sukses'); + return; + } + + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => WillPopScope( + onWillPop: () async => false, // Mencegah dialog ditutup dengan tombol back + child: AlertDialog( + title: Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.green.shade50, + shape: BoxShape.circle, + ), + child: Icon( + Icons.check_circle, + color: Colors.green.shade400, + size: 24, + ), + ), + const SizedBox(width: 12), + const Expanded( + child: Text( + 'Pembayaran Berhasil', + style: TextStyle(fontSize: 18), + ), + ), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Pembayaran Anda telah berhasil diproses.', + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 14, + ), + ), + const SizedBox(height: 8), + Text( + 'Anda dapat melihat detail pembayaran pada halaman ini.', + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 14, + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + // Hanya tutup dialog, tidak keluar dari halaman payment + Navigator.of(context).pop(); + }, + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text( + 'Lihat Detail', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + ), + ElevatedButton( + onPressed: () { + // Tutup dialog dan kembali ke halaman sebelumnya + Navigator.of(context).pop(); + Navigator.of(context).pop(true); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text( + 'Kembali', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ], + ), + ), + ); + } + + void _startPaymentStatusCheck() { + // Cancel timer lama jika ada + for (var timer in _statusTimers) { + timer.cancel(); + } + _statusTimers.clear(); + + // Buat timer baru untuk pemeriksaan status - hanya memeriksa sekali saat awal dan setelah WebView ditutup + // Tidak lagi menggunakan timer berkala + + try { + // Hindari cek bertumpuk + if (_isCheckingStatus) return; + _isCheckingStatus = true; + + print('Mengecek status pembayaran awal... (${DateTime.now()})'); + // Coba periksa status secara manual terlebih dahulu + _midtransController.checkPaymentStatusManual(_bookingId).then((dynamic result) { + // Jika pemeriksaan manual gagal, gunakan metode normal + if ((result as Map)['success'] != true) { + return _midtransController.checkPaymentStatus(_bookingId); + } + return result; + }).then((dynamic result) { + final Map paymentResult = result as Map; + // Periksa kembali mounted setelah await, untuk mencegah update pada widget yang sudah di-dispose + if (!mounted) { + _isCheckingStatus = false; + return; + } + + _isCheckingStatus = false; + + if (paymentResult['success'] == true) { + // Jika status pembayaran berhasil + if (_midtransController.paymentStatus == 'settlement' || + _midtransController.paymentStatus == 'capture' || + _midtransController.paymentStatus == 'paid') { + // Pembayaran berhasil, tampilkan dialog + print('Status pembayaran: ${_midtransController.paymentStatus} - pembayaran berhasil!'); + + // Periksa kembali apakah masih mounted sebelum menampilkan dialog + if (mounted) { + // Tampilkan dialog sukses + _showPaymentSuccessDialog(); + } + } else { + // Pembayaran belum selesai + print('Status pembayaran: ${_midtransController.paymentStatus} - masih menunggu'); + if (mounted) { + setState(() { + // Update UI jika diperlukan + }); + } + } + } else { + print('Gagal memeriksa status: ${paymentResult['message']}'); + } + }).catchError((e) { + _isCheckingStatus = false; + print('Error saat cek status: $e'); + }); + } catch (e) { + _isCheckingStatus = false; + print('Error saat cek status: $e'); + } + } + + @override + Widget build(BuildContext context) { + final midtransController = Provider.of(context); + + // Pastikan harga yang diterima dari API sudah dalam format yang benar + print('DEBUG: Original price from widget: ${widget.totalPrice}'); + print('DEBUG: Parsed numeric price from widget: $_numericTotalPrice'); + print('DEBUG: MidtransController payment data: ${midtransController.paymentData}'); + + // Prioritaskan mengambil total_price dari API response jika tersedia + int priceToDisplay = _numericTotalPrice; + if (midtransController.paymentData['total_price'] != null) { + // Parse total_price dari API yang lebih akurat + String apiPrice = midtransController.paymentData['total_price'].toString(); + print('DEBUG: API price string: $apiPrice'); + + // Bersihkan string harga dari karakter non-angka (kecuali titik desimal) + String cleanApiPrice = apiPrice.replaceAll(RegExp(r'[^0-9.]'), ''); + print('DEBUG: Clean API price: $cleanApiPrice'); + + // Jika ada titik desimal, ambil bagian sebelum desimal + if (cleanApiPrice.contains('.')) { + cleanApiPrice = cleanApiPrice.split('.')[0]; + } + print('DEBUG: Final clean API price: $cleanApiPrice'); + + // Parse ke integer + int apiPriceInt = int.tryParse(cleanApiPrice) ?? _numericTotalPrice; + print('DEBUG: API price parsed to int: $apiPriceInt'); + + // Gunakan nilai dari API jika valid + if (apiPriceInt > 0) { + priceToDisplay = apiPriceInt; + } + } + + print('DEBUG: Final price to display: $priceToDisplay'); + + // Biaya tambahan + const int paymentServiceFee = 4000; + // const int tailorServiceFee = 1000; + + // Total akhir + final int finalTotal = priceToDisplay + paymentServiceFee; + + // Format rupiah menggunakan angka yang benar + final formattedBasePrice = _formatRupiah(priceToDisplay); + final formattedPaymentFee = _formatRupiah(paymentServiceFee); + // final formattedTailorFee = _formatRupiah(tailorServiceFee); + final formattedTotalPrice = _formatRupiah(finalTotal); + + print('DEBUG: Final formatted price: $formattedTotalPrice'); + + return Scaffold( + appBar: AppBar( + title: const Text('Pembayaran'), + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + actions: [ + // Tombol refresh manual untuk status pembayaran + IconButton( + icon: const Icon(Icons.refresh), + tooltip: 'Refresh status pembayaran', + onPressed: () async { + setState(() { + _isLoading = true; + }); + try { + // Coba periksa status secara manual terlebih dahulu + final manualResult = await _midtransController.checkPaymentStatusManual(_bookingId); + if (!manualResult['success']) { + // Jika gagal, gunakan metode normal + await _midtransController.checkPaymentStatus(_bookingId); + } + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Status pembayaran diperbarui'), + duration: Duration(seconds: 1), + ), + ); + } catch (e) { + _showErrorSnackBar('Gagal memperbarui status: $e'); + } finally { + setState(() { + _isLoading = false; + }); + } + }, + ), + ], + ), + body: midtransController.isLoading || _isLoading + ? const Center(child: CircularProgressIndicator()) + : !_isInitialized + ? const Center(child: Text('Memuat halaman pembayaran...')) + : RefreshIndicator( + onRefresh: () async { + try { + await _midtransController.checkPaymentStatus(_bookingId); + } catch (e) { + if (mounted) { + _showErrorSnackBar('Gagal memeriksa status: $e'); + } + } + }, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Info refresh + Container( + width: double.infinity, + margin: const EdgeInsets.only(bottom: 16), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade200), + ), + child: Row( + children: [ + Icon(Icons.info_outline, + color: Colors.blue.shade800, size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Cek Status Pembayaran', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.blue.shade800, + fontSize: 14, + ), + ), + const SizedBox(height: 4), + Text( + 'Tekan tombol refresh di pojok kanan atas atau tarik layar ke bawah untuk memperbarui status pembayaran secara manual', + style: TextStyle( + color: Colors.blue.shade800, + fontSize: 13, + ), + ), + ], + ), + ), + ], + ), + ), + + // Header payment page + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header dengan ikon + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF1A2552).withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.receipt_long, + color: Color(0xFF1A2552), + size: 20, + ), + ), + const SizedBox(width: 12), + const Text( + 'Ringkasan Pembayaran', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + const SizedBox(height: 16), + + // Kode transaksi + _buildInfoRow('Kode Transaksi', widget.transactionCode), + + // Status pembayaran dengan lencana + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + 'Status Pembayaran', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + ), + const Text(': '), + Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: _getStatusColor(midtransController.paymentStatus).withOpacity(0.1), + borderRadius: BorderRadius.circular(6), + border: Border.all( + color: _getStatusColor(midtransController.paymentStatus), + width: 1, + ), + ), + child: Text( + MidtransService.getPaymentStatusText(midtransController.paymentStatus), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: _getStatusColor(midtransController.paymentStatus), + ), + ), + ), + ), + ], + ), + + const SizedBox(height: 20), + const Divider(), + const SizedBox(height: 16), + + // Rincian biaya layanan + // Item biaya dengan format yang lebih bagus + _buildPriceItem("Biaya Jahit", formattedBasePrice, isMain: true), + _buildPriceItem("Biaya Layanan Payment", formattedPaymentFee), + + + const SizedBox(height: 12), + const Divider(), + const SizedBox(height: 12), + + // Total + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Total Pembayaran', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + Text( + 'Rp $formattedTotalPrice', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + ], + ), + ), + + const SizedBox(height: 24), + + // Tombol pembayaran + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: midtransController.isPaymentInitiated ? () => _midtransController.openPaymentPage(context) : null, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text('Buka Halaman Pembayaran'), + ), + ), + const SizedBox(height: 16), + + // Catatan informasi + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.amber[50], + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.amber.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.info_outline, size: 18, color: Colors.amber[800]), + const SizedBox(width: 8), + Text( + 'Catatan Penting:', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.amber[900], + ), + ), + ], + ), + const SizedBox(height: 8), + const Text('1. Anda akan diarahkan ke halaman pembayaran Midtrans.'), + const Text('2. Pilih metode pembayaran yang Anda inginkan.'), + const Text('3. Setelah pembayaran berhasil, Anda akan kembali ke aplikasi.'), + const Text('4. Tekan tombol refresh di pojok kanan atas untuk memeriksa status pembayaran.'), + const Text('5. Status mungkin tidak langsung berubah, mohon tunggu beberapa saat.'), + ], + ), + ), + ], + ), + ), + ), + ); + } + + // Helper untuk menampilkan item harga + Widget _buildPriceItem(String label, String price, {bool isMain = false}) { + return Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: TextStyle( + fontSize: isMain ? 15 : 14, + fontWeight: isMain ? FontWeight.w600 : FontWeight.normal, + color: isMain ? const Color(0xFF1A2552) : Colors.grey.shade700, + ), + ), + Text( + 'Rp $price', + style: TextStyle( + fontSize: isMain ? 15 : 14, + fontWeight: isMain ? FontWeight.w600 : FontWeight.w500, + color: isMain ? const Color(0xFF1A2552) : Colors.grey.shade800, + ), + ), + ], + ), + ); + } + + // Widget untuk menampilkan baris informasi + Widget _buildInfoRow(String label, String value, {Color? valueColor}) { + return Padding( + padding: const EdgeInsets.only(bottom: 12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + label, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + ), + const Text(': '), + Expanded( + child: Text( + value, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: valueColor ?? const Color(0xFF1A2552), + ), + ), + ), + ], + ), + ); + } + + // Helper untuk mendapatkan warna berdasarkan status + Color _getStatusColor(String status) { + switch (status.toLowerCase()) { + case 'settlement': + case 'capture': + case 'paid': + return Colors.green.shade700; + case 'pending': + return Colors.orange.shade700; + case 'deny': + case 'cancel': + case 'expire': + return Colors.red.shade700; + default: + return Colors.grey.shade700; + } + } + + void _showCopyLinkDialog(String url) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Tidak dapat membuka halaman pembayaran'), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Kami tidak dapat membuka halaman pembayaran secara otomatis. Silakan salin link pembayaran berikut dan buka di browser Anda:', + ), + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(4), + ), + child: Row( + children: [ + Expanded( + child: Text( + url, + style: const TextStyle(fontWeight: FontWeight.w500), + ), + ), + IconButton( + icon: const Icon(Icons.copy), + onPressed: () { + Clipboard.setData(ClipboardData(text: url)); + Navigator.pop(context); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Link pembayaran disalin ke clipboard')), + ); + }, + ), + ], + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Tutup'), + ), + ], + ), + ); + } + + // Fungsi untuk memformat rupiah dengan pemisah titik sebagai ribuan + String _formatRupiah(int value) { + print('DEBUG: Format Rupiah - Input value: $value'); + + // Format khusus tanpa desimal, dengan pemisah ribuan berupa titik + final formatter = NumberFormat('#,###', 'id'); + formatter.minimumFractionDigits = 0; + formatter.maximumFractionDigits = 0; + + // Format angka dan ganti koma dengan titik + String formatted = formatter.format(value); + formatted = formatted.replaceAll(',', '.'); + + print('DEBUG: Format Rupiah - Final formatted: $formatted'); + + return formatted; + } + + @override + void dispose() { + // Batalkan semua timer untuk mencegah callback yang tidak diinginkan + for (var timer in _statusTimers) { + timer.cancel(); + } + _statusTimers.clear(); + super.dispose(); + } +} diff --git a/TA_android/lib/pages/costumer/profile/profile_page.dart b/TA_android/lib/pages/costumer/profile/profile_page.dart new file mode 100644 index 0000000..47c4e65 --- /dev/null +++ b/TA_android/lib/pages/costumer/profile/profile_page.dart @@ -0,0 +1,691 @@ +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:provider/provider.dart'; +import 'dart:io'; +import '../../../core/widgets/custom_button.dart'; +import '../../../core/controllers/auth_controller.dart'; +import '../../../core/controllers/profile_controller.dart'; +import '../../../core/routes/routes.dart'; +import '../../../core/providers/user_provider.dart'; +import '../../../core/models/user_model.dart'; +import '../../../core/utils/url_helper.dart'; +import '../../../core/utils/logger.dart'; +// ignore_for_file: avoid_print + +class ProfilePage extends StatefulWidget { + const ProfilePage({super.key}); + + @override + State createState() => _ProfilePageState(); +} + +class _ProfilePageState extends State { + final AuthController _authController = AuthController(); + final ProfileController _profileController = ProfileController(); + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _phoneController = TextEditingController(); + final TextEditingController _addressController = TextEditingController(); + File? _profileImage; + bool _isLoading = false; + bool _isUploadingPhoto = false; + bool _isLoadingProfile = true; + + @override + void initState() { + super.initState(); + _loadUserData(); + _fetchProfileFromAPI(); + } + + Future _fetchProfileFromAPI() async { + setState(() { + _isLoadingProfile = true; + }); + + try { + // Gunakan ProfileController untuk memuat profil dari API + AppLogger.info('Memuat profil dari API', tag: 'ProfilePage'); + + final success = await _profileController.loadUserProfile(context); + + if (success) { + AppLogger.info('Profil berhasil dimuat dari API', tag: 'ProfilePage'); + // Perbarui data form dengan data terbaru + _loadUserData(); + } else { + AppLogger.error('Gagal memuat profil dari API', tag: 'ProfilePage'); + } + } catch (e) { + AppLogger.error('Exception saat memuat profil dari API', + error: e, tag: 'ProfilePage'); + } finally { + if (mounted) { + setState(() { + _isLoadingProfile = false; + }); + } + } + } + + void _loadUserData() { + final userProvider = Provider.of(context, listen: false); + if (userProvider.user != null) { + setState(() { + _nameController.text = userProvider.user!.name; + _emailController.text = userProvider.user!.email; + _phoneController.text = userProvider.user!.phoneNumber; + _addressController.text = userProvider.user!.address; + }); + } + } + + Future _pickImage() async { + // Cegah membuka picker jika sudah aktif atau sedang mengupload + if (_isUploadingPhoto) { + AppLogger.warning('Image picker sudah aktif, abaikan request', + tag: 'ProfilePage'); + return; + } + + try { + setState(() { + _isUploadingPhoto = true; + }); + + final ImagePicker picker = ImagePicker(); + final XFile? image = await picker.pickImage( + source: ImageSource.gallery, + imageQuality: 70, // Kompresi kualitas gambar untuk mengurangi ukuran + ); + + if (image != null) { + setState(() { + _profileImage = File(image.path); + }); + + // Upload foto langsung setelah dipilih + await _uploadProfilePhoto(); + } else { + // User membatalkan pemilihan foto + setState(() { + _isUploadingPhoto = false; + }); + } + } catch (e) { + AppLogger.error('Error saat memilih gambar', + error: e, tag: 'ProfilePage'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal memilih foto: $e'), + backgroundColor: Colors.red, + ), + ); + setState(() { + _isUploadingPhoto = false; + }); + } + } + + Future _uploadProfilePhoto() async { + if (_profileImage == null) return; + + setState(() { + _isUploadingPhoto = true; + }); + + try { + // Upload foto profil menggunakan ProfileController + final success = + await _profileController.uploadProfilePhoto(context, _profileImage!); + + if (success) { + setState(() { + // Reset _profileImage setelah berhasil upload + _profileImage = null; + }); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal mengupload foto: $e'), + backgroundColor: Colors.red, + ), + ); + } finally { + setState(() { + _isUploadingPhoto = false; + }); + } + } + + Future _updateProfile() async { + setState(() { + _isLoading = true; + }); + + try { + // Siapkan data untuk update + final Map updateData = { + 'name': _nameController.text, + 'email': _emailController.text, // tambahkan email + 'phone_number': _phoneController.text, + 'address': _addressController.text, + }; + + // Tambahkan latitude dan longitude jika tersedia + final userProvider = Provider.of(context, listen: false); + if (userProvider.user?.latitude != null && + userProvider.user?.longitude != null) { + updateData['latitude'] = userProvider.user!.latitude; + updateData['longitude'] = userProvider.user!.longitude; + } + + AppLogger.debug('Data yang akan diupdate: $updateData', + tag: 'ProfilePage'); + + // Gunakan ProfileController untuk update profil + final success = + await _profileController.updateProfile(context, updateData); + + if (success) { + // Refresh data setelah berhasil update + await _profileController.loadUserProfile(context); + } + } catch (e) { + AppLogger.error('Error saat update profil', error: e, tag: 'ProfilePage'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal memperbarui profil: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + // Tambahkan fungsi untuk refresh profile + Future _refreshProfile() async { + if (!mounted) return; + + setState(() { + _isLoadingProfile = true; + }); + + try { + AppLogger.info('Memuat ulang profil pengguna', tag: 'ProfilePage'); + await _fetchProfileFromAPI(); + + AppLogger.info('Profil berhasil dimuat ulang', tag: 'ProfilePage'); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Profil berhasil diperbarui'), + backgroundColor: Colors.green, + ), + ); + } catch (e) { + AppLogger.error('Gagal memuat ulang profil', + error: e, tag: 'ProfilePage'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal memperbarui profil: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoadingProfile = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + // Helper method untuk memastikan URL lengkap + String getFullPhotoUrl(String? photoUrl) { + if (photoUrl == null || photoUrl.isEmpty) { + print('DEBUG COSTUMER PROFILE: Photo URL is null or empty'); + return ''; + } + + print('DEBUG COSTUMER PROFILE: Processing photo URL: $photoUrl'); + + // Gunakan UrlHelper untuk mendapatkan URL lengkap + final fullUrl = UrlHelper.getFullImageUrl(photoUrl); + print('DEBUG COSTUMER PROFILE: Converted to full URL: $fullUrl'); + return fullUrl; + } + + return Consumer( + builder: (context, userProvider, child) { + final User? user = userProvider.user; + + // Jika tidak ada data user atau sedang memuat profil, tampilkan loading + if (user == null || _isLoadingProfile) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + // Log info user untuk debugging + print( + 'DEBUG COSTUMER PROFILE: User data loaded. Name: ${user.name}, Email: ${user.email}'); + print( + 'DEBUG COSTUMER PROFILE: Profile photo URL: ${user.profilePhoto}'); + + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: const Text( + 'Profil Pelanggan', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + centerTitle: true, + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + iconTheme: const IconThemeData(color: Color(0xFF1A2552)), + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios_new, size: 18), + onPressed: () { + // Kembali ke halaman utama + Navigator.pushReplacementNamed(context, AppRoutes.customerHome); + }, + ), + actions: [ + // Tambahkan tombol refresh di AppBar + IconButton( + icon: const Icon(Icons.refresh, color: Color(0xFF1A2552)), + onPressed: _refreshProfile, + ), + ], + ), + body: RefreshIndicator( + onRefresh: _refreshProfile, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Profile Image + Center( + child: Stack( + children: [ + Container( + width: 100, + height: 100, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey.shade300, + width: 1, + ), + ), + child: _buildProfileImage(user, getFullPhotoUrl), + ), + Positioned( + bottom: 0, + right: 0, + child: GestureDetector( + onTap: _isUploadingPhoto ? null : _pickImage, + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.3), + spreadRadius: 1, + blurRadius: 2, + offset: const Offset(0, 1), + ), + ], + ), + child: Icon( + Icons.camera_alt, + size: 20, + color: _isUploadingPhoto + ? Colors.grey.shade400 + : Colors.grey.shade700, + ), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + + // Email Verified Badge + if (user.emailVerifiedAt != null) + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.green.shade100, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.verified, + size: 16, color: Colors.green.shade700), + const SizedBox(width: 4), + Text( + 'Email Terverifikasi', + style: TextStyle( + fontSize: 12, + color: Colors.green.shade700, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + const SizedBox(height: 24), + + // Profile Form + _buildFormField( + label: 'Nama', + controller: _nameController, + ), + const SizedBox(height: 16), + + _buildFormField( + label: 'Email', + controller: _emailController, + readOnly: true, // Email tidak bisa diubah + ), + const SizedBox(height: 16), + + _buildFormField( + label: 'No. Handphone', + controller: _phoneController, + ), + const SizedBox(height: 16), + + _buildFormField( + label: 'Alamat', + controller: _addressController, + ), + + // Tambahkan bagian lokasi jika ada + if (user.latitude != null && user.longitude != null) + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Lokasi', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + const Icon(Icons.location_on, + color: Colors.red), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Latitude: ${user.latitude}, Longitude: ${user.longitude}', + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + ), + ], + ), + ), + + const SizedBox(height: 32), + + // Update Button + CustomButton( + text: 'Update Profil', + onPressed: _updateProfile, + isLoading: _isLoading, + borderRadius: 8, + backgroundColor: const Color(0xFF1E3A8A), + ), + + const SizedBox(height: 24), + + // Logout Button + CustomButton( + text: 'Logout', + onPressed: () { + // Tampilkan dialog konfirmasi logout + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Konfirmasi Logout'), + content: const Text( + 'Apakah Anda yakin ingin keluar dari aplikasi?'), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); // Tutup dialog + }, + child: const Text('Batal'), + ), + TextButton( + onPressed: () async { + // Tampilkan loading + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return const Center( + child: CircularProgressIndicator(), + ); + }, + ); + + // Proses logout + await _authController.logout(context); + + // Tutup loading dialog + Navigator.pop(context); + + // Tutup dialog konfirmasi + Navigator.pop(context); + + // Navigasi ke halaman login + Navigator.pushNamedAndRemoveUntil(context, + AppRoutes.login, (route) => false); + + // Tampilkan pesan sukses + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Berhasil logout'), + backgroundColor: Colors.green, + ), + ); + }, + child: const Text('Logout', + style: TextStyle(color: Colors.red)), + ), + ], + ), + ); + }, + borderRadius: 8, + backgroundColor: Colors.red, + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + // Helper method untuk membangun tampilan foto profil + Widget _buildProfileImage( + User user, String Function(String?) getFullPhotoUrl) { + if (_isUploadingPhoto) { + return ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + color: Colors.grey.shade200, + child: const Center( + child: CircularProgressIndicator(), + ), + ), + ); + } + + if (_profileImage != null) { + return ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Image.file( + _profileImage!, + fit: BoxFit.cover, + ), + ); + } + + if (user.profilePhoto != null && user.profilePhoto!.isNotEmpty) { + return ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Image.network( + getFullPhotoUrl(user.profilePhoto), + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) { + print( + 'DEBUG COSTUMER PROFILE: Profile image loaded successfully'); + return child; + } + print('DEBUG COSTUMER PROFILE: Loading profile image...'); + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + print( + 'DEBUG COSTUMER PROFILE: Error loading profile image: $error'); + print( + 'DEBUG COSTUMER PROFILE: Failed URL: ${getFullPhotoUrl(user.profilePhoto)}'); + return const Icon( + Icons.person, + size: 40, + color: Colors.grey, + ); + }, + ), + ); + } + + // Default image + return ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Image.asset( + 'assets/images/tailor_default.png', + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + color: Colors.grey.shade200, + child: const Icon( + Icons.person, + size: 40, + color: Colors.grey, + ), + ); + }, + ), + ); + } + + Widget _buildFormField({ + required String label, + required TextEditingController controller, + bool readOnly = false, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + TextField( + controller: controller, + readOnly: readOnly, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + contentPadding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + filled: true, + fillColor: readOnly ? Colors.grey.shade100 : Colors.white, + ), + ), + ], + ); + } + + @override + void dispose() { + _nameController.dispose(); + _emailController.dispose(); + _phoneController.dispose(); + _addressController.dispose(); + super.dispose(); + } +} diff --git a/TA_android/lib/pages/debug/debug_page.dart b/TA_android/lib/pages/debug/debug_page.dart new file mode 100644 index 0000000..21a563e --- /dev/null +++ b/TA_android/lib/pages/debug/debug_page.dart @@ -0,0 +1,370 @@ +import 'package:flutter/material.dart'; +import '../../core/services/api_service.dart'; +import '../../core/services/shared_prefs_helper.dart'; + +class DebugPage extends StatefulWidget { + const DebugPage({super.key}); + + @override + State createState() => _DebugPageState(); +} + +class _DebugPageState extends State { + bool _isLoading = false; + Map _tokenStatus = {}; + final TextEditingController _tokenController = TextEditingController(); + + @override + void initState() { + super.initState(); + _checkTokenStatus(); + } + + Future _checkTokenStatus() async { + setState(() { + _isLoading = true; + }); + + try { + final status = await ApiService.checkTokenStatus(); + setState(() { + _tokenStatus = status; + }); + } catch (e) { + print('Error checking token status: $e'); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + Future _testSharedPrefs() async { + setState(() { + _isLoading = true; + }); + + try { + final result = await SharedPrefsHelper.checkIfWorking(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'SharedPreferences ${result ? "berfungsi dengan baik" : "bermasalah"}'), + backgroundColor: result ? Colors.green : Colors.red, + ), + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error: $e'), + backgroundColor: Colors.red, + ), + ); + } finally { + setState(() { + _isLoading = false; + }); + _checkTokenStatus(); + } + } + + Future _fixSharedPrefs() async { + setState(() { + _isLoading = true; + }); + + try { + final result = await SharedPrefsHelper.tryToFix(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Memperbaiki SharedPreferences ${result ? "berhasil" : "gagal"}'), + backgroundColor: result ? Colors.green : Colors.red, + ), + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error: $e'), + backgroundColor: Colors.red, + ), + ); + } finally { + setState(() { + _isLoading = false; + }); + _checkTokenStatus(); + } + } + + Future _saveTokenManually() async { + if (_tokenController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Token tidak boleh kosong'), + backgroundColor: Colors.red, + ), + ); + return; + } + + setState(() { + _isLoading = true; + }); + + try { + await ApiService.saveToken(_tokenController.text); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Token berhasil disimpan'), + backgroundColor: Colors.green, + ), + ); + _tokenController.clear(); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error: $e'), + backgroundColor: Colors.red, + ), + ); + } finally { + setState(() { + _isLoading = false; + }); + _checkTokenStatus(); + } + } + + Future _removeTokenManually() async { + setState(() { + _isLoading = true; + }); + + try { + await ApiService.removeToken(); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Token berhasil dihapus'), + backgroundColor: Colors.green, + ), + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error: $e'), + backgroundColor: Colors.red, + ), + ); + } finally { + setState(() { + _isLoading = false; + }); + _checkTokenStatus(); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Debug Shared Preferences'), + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSection( + title: 'Status Token', + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildStatusItem( + 'SharedPreferences Status', + _tokenStatus['sharedPrefsWorking'] == true + ? 'Berfungsi' + : 'Bermasalah', + _tokenStatus['sharedPrefsWorking'] == true + ? Colors.green + : Colors.red, + ), + _buildStatusItem( + 'Token di SharedPreferences', + _tokenStatus['tokenInSharedPrefs'] == true + ? 'Ada' + : 'Tidak Ada', + _tokenStatus['tokenInSharedPrefs'] == true + ? Colors.green + : Colors.orange, + ), + if (_tokenStatus['tokenValue'] != null) + _buildStatusItem( + 'Nilai Token', + '${_tokenStatus['tokenValue']}', + Colors.blue, + ), + _buildStatusItem( + 'Token di Memory', + _tokenStatus['tokenInMemory'] == true + ? 'Ada' + : 'Tidak Ada', + _tokenStatus['tokenInMemory'] == true + ? Colors.green + : Colors.orange, + ), + if (_tokenStatus['memoryTokenValue'] != null) + _buildStatusItem( + 'Nilai Token Memory', + '${_tokenStatus['memoryTokenValue']}', + Colors.blue, + ), + if (_tokenStatus['error'] != null) + _buildStatusItem( + 'Error', + '${_tokenStatus['error']}', + Colors.red, + ), + ], + ), + ), + const SizedBox(height: 16), + _buildSection( + title: 'Aksi', + child: Column( + children: [ + ElevatedButton( + onPressed: _testSharedPrefs, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + minimumSize: const Size(double.infinity, 45), + ), + child: const Text('Test SharedPreferences'), + ), + const SizedBox(height: 8), + ElevatedButton( + onPressed: _fixSharedPrefs, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.orange, + foregroundColor: Colors.white, + minimumSize: const Size(double.infinity, 45), + ), + child: const Text('Perbaiki SharedPreferences'), + ), + const SizedBox(height: 8), + ElevatedButton( + onPressed: _removeTokenManually, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + foregroundColor: Colors.white, + minimumSize: const Size(double.infinity, 45), + ), + child: const Text('Hapus Token'), + ), + const SizedBox(height: 16), + TextField( + controller: _tokenController, + decoration: const InputDecoration( + labelText: 'Token', + border: OutlineInputBorder(), + hintText: 'Masukkan token manual', + ), + ), + const SizedBox(height: 8), + ElevatedButton( + onPressed: _saveTokenManually, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + foregroundColor: Colors.white, + minimumSize: const Size(double.infinity, 45), + ), + child: const Text('Simpan Token Manual'), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _checkTokenStatus, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + minimumSize: const Size(double.infinity, 45), + ), + child: const Text('Refresh Status'), + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildSection({required String title, required Widget child}) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 16), + child, + ], + ), + ); + } + + Widget _buildStatusItem(String label, String value, Color valueColor) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: const TextStyle( + fontSize: 14, + color: Colors.black87, + ), + ), + Text( + value, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: valueColor, + ), + ), + ], + ), + ); + } + + @override + void dispose() { + _tokenController.dispose(); + super.dispose(); + } +} diff --git a/TA_android/lib/pages/onboarding_page.dart b/TA_android/lib/pages/onboarding_page.dart new file mode 100644 index 0000000..205b5e8 --- /dev/null +++ b/TA_android/lib/pages/onboarding_page.dart @@ -0,0 +1,164 @@ +import 'package:flutter/material.dart'; + +class OnboardingPage extends StatelessWidget { + const OnboardingPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: Column( + children: [ + // Status bar padding + Container( + height: MediaQuery.of(context).padding.top, + color: Colors.white, + ), + // Main content + Expanded( + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Logo + Expanded( + flex: 5, + child: Container( + padding: const EdgeInsets.only(top: 70), + alignment: Alignment.center, + child: Image.asset( + 'assets/images/LogoGelap.png', + width: 500, + height: 500, + fit: BoxFit.contain, + ), + ), + ), + // Text and buttons + Expanded( + flex: 4, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text( + 'Nikmati kemudahan Jahit', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + const Text( + 'Anda Bersama TailorHub', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + const SizedBox(height: 25), + ElevatedButton( + onPressed: () { + Navigator.pushReplacementNamed( + context, '/register-option'); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + minimumSize: const Size(150, 40), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 0, + ), + child: const Text( + 'Buat Akun', + style: TextStyle(fontSize: 14), + ), + ), + const SizedBox(height: 12), + Padding( + padding: const EdgeInsets.only(top: 5.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Memiliki Akun?', + style: TextStyle( + color: Colors.grey, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 3), + GestureDetector( + onTap: () { + Navigator.pushNamed(context, '/login'); + }, + child: const Text( + 'Masuk', + style: TextStyle( + color: Color(0xFF1A2552), + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + // Navigation bar + Container( + height: 50, + padding: const EdgeInsets.symmetric(vertical: 8), + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 8, + height: 8, + margin: const EdgeInsets.symmetric(horizontal: 4), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey[300], + ), + ), + Container( + width: 8, + height: 8, + margin: const EdgeInsets.symmetric(horizontal: 4), + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF1A2552), + ), + ), + Container( + width: 8, + height: 8, + margin: const EdgeInsets.symmetric(horizontal: 4), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey[300], + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/TA_android/lib/pages/register_option_page.dart b/TA_android/lib/pages/register_option_page.dart new file mode 100644 index 0000000..118a6c0 --- /dev/null +++ b/TA_android/lib/pages/register_option_page.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import 'auth/register_tailor_page.dart'; + +class RegisterOptionPage extends StatelessWidget { + const RegisterOptionPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: Column( + children: [ + // Status bar padding + Container( + height: MediaQuery.of(context).padding.top, + color: Colors.white, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 30), + const Text( + 'Selamat datang di TailorHub', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + const SizedBox(height: 40), + // Kartu 1: Pelanggan + Container( + width: 350, + height: 200, + decoration: BoxDecoration( + color: const Color(0xFF1A2552), + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 25), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 20), + const Text( + 'Kamu lagi mencari penjahit?', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 15, + ), + ), + const SizedBox(height: 5), + const Text( + 'yuk daftar sebagai pelanggan', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 15, + ), + ), + const SizedBox(height: 35), + Align( + alignment: Alignment.center, + child: ElevatedButton( + onPressed: () { + Navigator.pushNamed( + context, '/register-customer'); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: const Color(0xFF1A2552), + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + minimumSize: const Size(160, 36), + ), + child: const Text( + 'Daftar Pelanggan', + style: TextStyle( + fontSize: 15, + ), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 20), + // Kartu 2: Penjahit + Container( + width: 350, + height: 200, + decoration: BoxDecoration( + color: const Color(0xFF1A2552), + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 25), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 20), + const Text( + 'Kamu lagi mitra penjahit?', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 15, + ), + ), + const SizedBox(height: 5), + const Text( + 'yuk bergabung bersama TailorHub', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 15, + ), + ), + const SizedBox(height: 35), + Align( + alignment: Alignment.center, + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const RegisterTailorPage(), + ), + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: const Color(0xFF1A2552), + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + minimumSize: const Size(160, 36), + ), + child: const Text( + 'Daftar Penjahit', + style: TextStyle( + fontSize: 15, + ), + ), + ), + ), + ], + ), + ), + Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 10, + height: 10, + margin: const EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey[300], + ), + ), + Container( + width: 10, + height: 10, + margin: const EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey[300], + ), + ), + Container( + width: 10, + height: 10, + margin: const EdgeInsets.symmetric(horizontal: 5), + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF1A2552), + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/TA_android/lib/pages/splash_screen.dart b/TA_android/lib/pages/splash_screen.dart new file mode 100644 index 0000000..0534fb1 --- /dev/null +++ b/TA_android/lib/pages/splash_screen.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; +import '../core/routes/routes.dart'; // Import untuk menggunakan konstanta rute +import '../core/services/auth_service.dart'; +import '../core/providers/user_provider.dart'; +import 'package:provider/provider.dart'; + +class SplashScreen extends StatefulWidget { + const SplashScreen({super.key}); + + @override + State createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + int _debugTapCount = 0; + final int _requiredTapsForDebug = 7; + DateTime? _lastTapTime; + bool _timerCompleted = false; + + void _handleDebugTap() { + final now = DateTime.now(); + + // Reset counter jika taps terlalu lambat (lebih dari 3 detik) + if (_lastTapTime != null && now.difference(_lastTapTime!).inSeconds > 3) { + _debugTapCount = 0; + } + + _lastTapTime = now; + _debugTapCount++; + + if (_debugTapCount >= _requiredTapsForDebug) { + _debugTapCount = 0; // Reset counter + + // Buka halaman debug + Navigator.pushNamed(context, AppRoutes.debug); + } + } + + @override + void initState() { + super.initState(); + _checkAuthAndNavigate(); + } + + Future _checkAuthAndNavigate() async { + // Tunggu 3 detik untuk menampilkan splash screen + await Future.delayed(const Duration(seconds: 3)); + + if (!mounted) return; + + // Periksa status autentikasi + final authData = await AuthService.getAuthData(); + + if (!mounted) return; + + setState(() { + _timerCompleted = true; + }); + + if (authData != null) { + // Muat data user sebelum navigasi + final userProvider = Provider.of(context, listen: false); + final success = await userProvider.loadUserFromPrefs(); + + if (!mounted) return; + + if (success) { + // Jika berhasil memuat data user, arahkan ke halaman yang sesuai + final route = authData['role'] == 'pelanggan' + ? AppRoutes.customerHome + : AppRoutes.tailorHome; + Navigator.pushReplacementNamed(context, route); + } else { + // Jika gagal memuat data user, arahkan ke login + Navigator.pushReplacementNamed(context, AppRoutes.login); + } + } else { + // Jika belum login, arahkan ke onboarding + Navigator.pushReplacementNamed(context, AppRoutes.onboarding); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFF1A2552), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: _timerCompleted + ? null + : _handleDebugTap, // Hanya aktif sebelum timer selesai + child: Image.asset( + 'assets/images/LogoPutih.png', + width: 350, + height: 350, + ), + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/pages/tailor/home/home_page.dart b/TA_android/lib/pages/tailor/home/home_page.dart new file mode 100644 index 0000000..37a8efd --- /dev/null +++ b/TA_android/lib/pages/tailor/home/home_page.dart @@ -0,0 +1,797 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import '../../../core/providers/user_provider.dart'; +import '../../../core/models/user_model.dart'; +import '../../../core/services/api_service.dart'; +import '../../../core/controllers/wallet_wd_controller.dart'; +import '../schedule/schedule_page.dart'; +import '../../../core/utils/app_routes.dart'; +// ignore_for_file: avoid_print + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + // Format currency + final currencyFormat = NumberFormat.currency( + locale: 'id', + symbol: 'Rp ', + decimalDigits: 0, + ); + + // State variables untuk data dashboard + List> _incomingBookings = []; + int _currentMonthEarnings = 0; + int _totalEarnings = 0; + double _averageRating = 0; + int _totalCompletedOrders = 0; + bool _isLoading = true; + String _errorMessage = ''; + late WalletWDController _walletController; + + @override + void initState() { + super.initState(); + _loadDashboardData(); + _walletController = Provider.of(context, listen: false); + _loadWalletData(); + } + + // Fungsi untuk mengambil data dashboard + Future _loadDashboardData() async { + setState(() { + _isLoading = true; + _errorMessage = ''; + }); + + try { + final result = await ApiService.getTailorDashboard(); + + setState(() { + _isLoading = false; + + if (result['success']) { + final data = result['data']; + + // Update state variables dengan konversi tipe data yang benar + _incomingBookings = + List>.from(data['incoming_bookings'] ?? []); + + // Konversi string ke int untuk earnings + _currentMonthEarnings = + _parseStringToInt(data['current_month_earnings']); + _totalEarnings = _parseStringToInt(data['total_earnings']); + + // Pastikan rating dikonversi dengan benar ke double + _averageRating = _parseStringToDouble(data['average_rating']); + + // Konversi total orders ke int + _totalCompletedOrders = + _parseStringToInt(data['total_completed_orders']); + + print('DEBUG: Dashboard data loaded successfully'); + } else { + _errorMessage = result['message'] ?? 'Gagal memuat data dashboard'; + print('DEBUG: Failed to load dashboard data: $_errorMessage'); + } + }); + } catch (e) { + setState(() { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + }); + print('ERROR: Failed to load dashboard data: $e'); + } + } + + Future _loadWalletData() async { + await _walletController.fetchWalletInfo(); + } + + // Helper method untuk mengkonversi string ke int dengan aman + int _parseStringToInt(dynamic value) { + if (value == null) return 0; + + try { + if (value is int) return value; + if (value is double) return value.toInt(); + + if (value is String) { + // Hapus semua karakter non-numerik (seperti koma, titik, dll) + final cleanValue = value.replaceAll(RegExp(r'[^0-9.]'), ''); + + // Jika string mengandung titik desimal, konversi ke double dahulu + if (cleanValue.contains('.')) { + return double.parse(cleanValue).toInt(); + } + + return int.parse(cleanValue); + } + + return 0; + } catch (e) { + print('ERROR: Gagal konversi ke int: $e untuk nilai: $value'); + return 0; + } + } + + // Helper method untuk mengkonversi string ke double dengan aman + double _parseStringToDouble(dynamic value) { + if (value == null) return 0.0; + + try { + if (value is double) return value; + if (value is int) return value.toDouble(); + + if (value is String) { + // Hapus semua karakter non-numerik (kecuali titik desimal) + final cleanValue = value.replaceAll(RegExp(r'[^0-9.]'), ''); + return double.parse(cleanValue); + } + + return 0.0; + } catch (e) { + print('ERROR: Gagal konversi ke double: $e untuk nilai: $value'); + return 0.0; + } + } + + @override + Widget build(BuildContext context) { + return Consumer2( + builder: (context, userProvider, walletController, child) { + final User? user = userProvider.user; + + // Jika tidak ada data user, tampilkan loading + if (user == null) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: Row( + children: [ + // Foto profil + Container( + width: 35, + height: 35, + margin: const EdgeInsets.only(right: 10), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey.shade300, + border: Border.all( + color: Colors.grey.shade200, + width: 1, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(35), + child: user.profilePhoto != null && + user.profilePhoto!.isNotEmpty + ? Image.network( + _getFullProfilePhotoUrl(user.profilePhoto!), + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon( + Icons.person, + color: Colors.white, + size: 20, + ), + ); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return const Center( + child: SizedBox( + width: 15, + height: 15, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ), + ); + }, + ) + : Image.asset( + 'assets/images/tailor_default.png', + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon( + Icons.person, + color: Colors.white, + size: 20, + ), + ); + }, + ), + ), + ), + Text( + user.name, + style: const TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + actions: [ + IconButton( + icon: const Icon(Icons.calendar_month_outlined, + color: Color(0xFF1A2552)), + onPressed: () { + // Navigasi ke halaman kalender jadwal + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SchedulePage(), + ), + ); + }, + ), + IconButton( + icon: const Icon(Icons.refresh, color: Color(0xFF1A2552)), + onPressed: () { + _loadDashboardData(); + _loadWalletData(); + }, + ), + ], + ), + body: SafeArea( + child: _isLoading + ? const Center( + child: CircularProgressIndicator(), + ) + : _errorMessage.isNotEmpty + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.error_outline, + size: 48, + color: Colors.red, + ), + const SizedBox(height: 16), + Text( + _errorMessage, + textAlign: TextAlign.center, + style: const TextStyle( + color: Colors.red, + fontSize: 16, + ), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () { + _loadDashboardData(); + _loadWalletData(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + ), + child: const Text('Coba Lagi'), + ), + ], + ), + ) + : RefreshIndicator( + onRefresh: () async { + await Future.wait([ + _loadDashboardData(), + _loadWalletData(), + ]); + }, + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Banner card + _buildBannerCard(), + + const SizedBox(height: 24), + + // Wallet card + _buildWalletCard(walletController), + + const SizedBox(height: 24), + + // Total Penghasilan card + _buildIncomeCard(), + + const SizedBox(height: 24), + + // Statistik Card + _buildStatisticsCard(), + ], + ), + ), + ), + ), + ), + ); + }, + ); + } + + // Helper method untuk memastikan URL lengkap + String _getFullProfilePhotoUrl(String photoUrl) { + // Jika URL sudah lengkap, kembalikan apa adanya + if (photoUrl.startsWith('http')) { + return photoUrl; + } + + // Jika tidak, tambahkan base URL + return ApiService.getFullImageUrl(photoUrl); + } + + Widget _buildBannerCard() { + return Container( + width: double.infinity, + height: 150, + decoration: BoxDecoration( + color: const Color(0xFF1A2552), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 10, + offset: const Offset(0, 5), + ), + ], + ), + child: Stack( + children: [ + // Background design elements + Positioned( + right: -20, + bottom: -20, + child: Container( + width: 120, + height: 120, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + shape: BoxShape.circle, + ), + ), + ), + Positioned( + left: -40, + top: -40, + child: Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + shape: BoxShape.circle, + ), + ), + ), + + // Content + Padding( + padding: const EdgeInsets.all(20.0), + child: Row( + children: [ + // Text section + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Selamat Datang Kembali!', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + const SizedBox(height: 8), + Text( + 'Anda telah menyelesaikan $_totalCompletedOrders pesanan.', + style: const TextStyle( + fontSize: 14, + color: Colors.white, + ), + ), + const SizedBox(height: 12), + Row( + children: [ + // Rating indicator + Row( + children: [ + const Icon( + Icons.star, + color: Colors.amber, + size: 16, + ), + const SizedBox(width: 4), + Text( + _averageRating.toStringAsFixed(1), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ], + ), + ], + ), + ), + + // Image or icon + Container( + width: 60, + height: 60, + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: const Center( + child: Icon( + Icons.content_cut, + color: Color(0xFF1A2552), + size: 30, + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildWalletCard(WalletWDController walletController) { + final walletInfo = walletController.walletInfo; + final balance = walletInfo?.getBalanceAsDouble() ?? 0.0; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Saldo Wallet', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 12), + Container( + width: double.infinity, + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF1A2552), + Color(0xFF2C3E7B), + ], + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 10, + offset: const Offset(0, 5), + ), + ], + ), + child: Stack( + children: [ + // Background design elements + Positioned( + right: -20, + bottom: -20, + child: Container( + width: 120, + height: 120, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + shape: BoxShape.circle, + ), + ), + ), + Positioned( + left: -40, + top: -40, + child: Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + shape: BoxShape.circle, + ), + ), + ), + + // Content + Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.2), + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.account_balance_wallet, + color: Colors.white, + size: 24, + ), + ), + const SizedBox(width: 12), + const Text( + 'Total Saldo', + style: TextStyle( + fontSize: 14, + color: Colors.white70, + ), + ), + ], + ), + const SizedBox(height: 12), + Text( + currencyFormat.format(balance), + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton.icon( + onPressed: () { + // Navigate to withdrawal page + Navigator.pushNamed(context, AppRoutes.withdrawal); + }, + icon: const Icon(Icons.arrow_upward, size: 18), + label: const Text('Tarik Dana'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: const Color(0xFF1A2552), + elevation: 0, + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + ), + ), + TextButton.icon( + onPressed: () { + // Navigate to transaction history page + Navigator.pushNamed(context, AppRoutes.walletHistory); + }, + icon: const Icon(Icons.history, size: 18), + label: const Text('Riwayat'), + style: TextButton.styleFrom( + foregroundColor: Colors.white, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ], + ); + } + + Widget _buildIncomeCard() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Penghasilan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 12), + Container( + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Bulan ini', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + Text( + currencyFormat.format(_currentMonthEarnings), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + ), + const Divider(height: 1, color: Colors.grey), + Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Total', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + Text( + currencyFormat.format(_totalEarnings), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + ), + ], + ), + ), + ], + ); + } + + Widget _buildStatisticsCard() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Statistik', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 12), + Container( + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildStatisticItem( + icon: Icons.check_circle_outline, + color: Colors.green, + value: _totalCompletedOrders.toString(), + label: 'Selesai', + ), + _buildStatisticItem( + icon: Icons.star, + color: Colors.amber, + value: _averageRating.toStringAsFixed(1), + label: 'Rating', + ), + ], + ), + ), + ), + ], + ); + } + + Widget _buildStatisticItem({ + required IconData icon, + required Color color, + required String value, + required String label, + }) { + return Column( + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: color.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Center( + child: Icon( + icon, + color: color, + size: 24, + ), + ), + ), + const SizedBox(height: 8), + Text( + value, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: color, + ), + ), + Text( + label, + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + ], + ); + } +} diff --git a/TA_android/lib/pages/tailor/main_page.dart b/TA_android/lib/pages/tailor/main_page.dart new file mode 100644 index 0000000..b51242f --- /dev/null +++ b/TA_android/lib/pages/tailor/main_page.dart @@ -0,0 +1,116 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; +import 'home/home_page.dart'; +import 'order/order_page.dart'; +import 'profile/profile_page.dart'; +import '../../core/services/api_service.dart'; +import '../../core/routes/routes.dart'; +import '../../core/utils/logger.dart'; + +class MainPage extends StatefulWidget { + const MainPage({super.key}); + + @override + State createState() => _MainPageState(); +} + +class _MainPageState extends State { + int _currentIndex = 0; + DateTime? _lastBackPressTime; + + // Daftar halaman yang akan ditampilkan dalam TabBar + final List _pages = [ + const HomePage(), + const OrderPage(), + const ProfilePage(), + ]; + + @override + void initState() { + super.initState(); + _checkAuthentication(); + } + + Future _checkAuthentication() async { + // Periksa apakah token tersedia saat halaman dimuat + final token = await ApiService.getToken(); + if (token == null) { + AppLogger.warning('Halaman utama penjahit diakses tanpa token'); + // Redirect ke login + if (mounted) { + Navigator.pushNamedAndRemoveUntil( + context, + AppRoutes.loginTailor, + (route) => false, + ); + } + } + } + + // Fungsi untuk menangani tombol back + Future _onWillPop() async { + final now = DateTime.now(); + + if (_lastBackPressTime == null || + now.difference(_lastBackPressTime!) > const Duration(seconds: 2)) { + // Update waktu terakhir tekan back + _lastBackPressTime = now; + + // Tampilkan pesan + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Tekan sekali lagi untuk keluar'), + duration: Duration(seconds: 2), + ), + ); + + // Jangan keluar dari aplikasi + return false; + } + + // Keluar dari aplikasi + return true; + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: _onWillPop, + child: Scaffold( + body: _pages[_currentIndex], // Tampilkan halaman sesuai index + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + selectedItemColor: const Color(0xFF1A2552), + unselectedItemColor: Colors.grey, + backgroundColor: Colors.white, + elevation: 8, + type: BottomNavigationBarType.fixed, + showSelectedLabels: true, + showUnselectedLabels: true, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.home_outlined), + activeIcon: Icon(Icons.home), + label: 'Beranda', + ), + BottomNavigationBarItem( + icon: Icon(Icons.receipt_outlined), + activeIcon: Icon(Icons.receipt), + label: 'Pesanan', + ), + BottomNavigationBarItem( + icon: Icon(Icons.person_outline), + activeIcon: Icon(Icons.person), + label: 'Profile', + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/pages/tailor/order/order_detail_Page.dart b/TA_android/lib/pages/tailor/order/order_detail_Page.dart new file mode 100644 index 0000000..8263019 --- /dev/null +++ b/TA_android/lib/pages/tailor/order/order_detail_Page.dart @@ -0,0 +1,3645 @@ +import 'package:flutter/material.dart'; +import '../../../core/services/api_service.dart'; +import '../../../core/models/booking_model.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'dart:io'; +import 'package:image_picker/image_picker.dart'; +import 'package:provider/provider.dart'; +import '../../../core/controllers/booking_controller.dart'; +import 'package:intl/intl.dart'; +import 'package:intl/date_symbol_data_local.dart'; // Tambahkan import ini +// ignore_for_file: avoid_print + +class OrderDetailPage extends StatefulWidget { + final BookingModel booking; + + const OrderDetailPage({ + super.key, + required this.booking, + }); + + @override + State createState() => _OrderDetailPageState(); +} + +class _OrderDetailPageState extends State { + // Controllers + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _dateController = TextEditingController(); + final TextEditingController _rejectionReasonController = + TextEditingController(); + final TextEditingController _repairNotesController = TextEditingController(); + final TextEditingController _additionalNotesController = + TextEditingController(); + final TextEditingController _priceController = TextEditingController(); + final TextEditingController _completionNotesController = + TextEditingController(); + final TextEditingController _pickupDateController = TextEditingController(); + final TextEditingController _completionDateController = TextEditingController(); + + // Untuk ukuran pakaian + final Map _measurementControllers = {}; + + // Dropdown values + String _selectedServiceType = 'Jahit Baru'; + String _selectedCategory = 'Bawahan'; + + // Loading state + bool _isLoading = true; + bool _isProcessing = false; + bool _isSaving = false; + bool _isUpdatingPrice = false; + bool _isCompletingOrder = false; + bool _isCompletingPayment = false; + String _errorMessage = ''; + BookingModel? _booking; + + // Untuk foto kerusakan + String? _damagePhotoPath; + File? _damagePhotoFile; + bool _isUploadingPhoto = false; + + // Untuk foto hasil jahitan + String? _completionPhotoPath; + File? _completionPhotoFile; + bool _isUploadingCompletionPhoto = false; + + // Map untuk menyimpan ukuran berdasarkan kategori + final Map> _measurementsByCategory = { + 'Bawahan': [ + 'Panjang Celana', + 'Lingkar Pinggang', + 'Lingkar Pinggul', + 'Lingkar Paha', + 'Lingkar Lutut', + 'Lingkar Pergelangan Kaki', + ], + 'Atasan': [ + 'Panjang Baju', + 'Lingkar Lengan', + 'Lebar Pundak', + 'Lingkar Dada', + 'Panjang Lengan', + 'Lingkar Pinggang', + 'Kerung Lengan', + 'Lingkar Leher', + ], + 'Terusan': [ + 'Panjang Badan', + 'Lingkar Badan', + 'Lingkar Pinggang', + 'Lingkar Pinggul', + 'Panjang Rok/Dress', + 'Panjang Lengan', + 'Lebar Bahu', + 'Lingkar Lengan', + 'Lingkar Kerung', + ], + }; + + // Map untuk menyimpan ukuran yang dipilih + Map _selectedMeasurements = {}; + + // Tambahkan variabel baru untuk tanggal pengambilan + String? _selectedPickupDate; + + // Di bagian awal class _OrderDetailPageState, tambahkan fungsi formatRupiah + String _formatRupiah(String nominal) { + if (nominal.isEmpty) return ''; + + print('DEBUG: _formatRupiah formatting price: "$nominal"'); + + // Bersihkan nominal dari karakter non-angka + String cleanNominal = nominal.replaceAll(RegExp(r'[^0-9]'), ''); + if (cleanNominal.isEmpty) return ''; + + print('DEBUG: _formatRupiah cleaned nominal: "$cleanNominal"'); + + // Parse ke integer + int value = int.tryParse(cleanNominal) ?? 0; + print('DEBUG: _formatRupiah parsed integer value: "$value"'); + + // Format dengan pemisah ribuan + RegExp reg = RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'); + String result = value.toString().replaceAllMapped(reg, (Match match) => '${match[1]}.'); + + print('DEBUG: _formatRupiah formatted result: "$result"'); + + return result; + } + + // Tambahkan fungsi untuk membersihkan format rupiah + String _cleanRupiah(String nominal) { + if (nominal.isEmpty) return ''; + + // Tangani kasus dengan angka desimal - ambil hanya bagian sebelum titik desimal + if (nominal.contains('.')) { + nominal = nominal.split('.')[0]; + } + + // Bersihkan nominal dari karakter non-angka + String cleanNominal = nominal.replaceAll(RegExp(r'[^0-9]'), ''); + print('DEBUG: _cleanRupiah input: $nominal, output: $cleanNominal'); + + return cleanNominal; + } + + @override + void initState() { + super.initState(); + _fetchBookingDetail(); + + // Inisialisasi locale data untuk format tanggal Indonesia + initializeDateFormatting('id_ID', null); + + // Inisialisasi controller untuk semua ukuran yang mungkin + for (final category in _measurementsByCategory.keys) { + for (final measurement in _measurementsByCategory[category]!) { + _measurementControllers[measurement] = TextEditingController(); + } + } + + // Inisialisasi tanggal penyelesaian default (7 hari dari sekarang) + final DateTime defaultCompletionDate = DateTime.now().add(const Duration(days: 7)); + _completionDateController.text = DateFormat('yyyy-MM-dd').format(defaultCompletionDate); + } + + Future _fetchBookingDetail() async { + if (!mounted) return; + + setState(() { + _isLoading = true; + _errorMessage = ''; + }); + + try { + final result = await ApiService.getBookingDetail(widget.booking.id); + + if (!mounted) return; + + if (result['success']) { + // Simpan data booking lama untuk debugging + final oldBooking = _booking; + + // Perbarui data booking dengan data terbaru + final newBooking = BookingModel.fromJson(result['booking']); + + // Debug log untuk membantu debugging + print('DEBUG: Refresh data booking berhasil'); + print('DEBUG: Harga lama: ${oldBooking?.totalPrice}, Harga baru: ${newBooking.totalPrice}'); + print('DEBUG: Tanggal selesai lama: ${oldBooking?.completionDate}, Tanggal selesai baru: ${newBooking.completionDate}'); + print('DEBUG: Foto desain: ${newBooking.designPhoto}'); + + setState(() { + _booking = newBooking; + _isLoading = false; + + // Perbarui controller harga jika perlu + if (newBooking.totalPrice != null && newBooking.totalPrice!.isNotEmpty) { + _priceController.text = _cleanRupiah(newBooking.totalPrice!); + } + + // Perbarui controller tanggal selesai jika perlu + if (newBooking.completionDate != null && newBooking.completionDate!.isNotEmpty) { + _completionDateController.text = newBooking.completionDate!; + } + + // Inisialisasi ulang data + _initializeData(); + }); + } else { + setState(() { + _isLoading = false; + _errorMessage = result['message']; + }); + } + } catch (e) { + if (!mounted) return; + + setState(() { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + }); + + print('ERROR: Gagal mengambil detail booking: $e'); + } + } + + void _initializeData() { + if (_booking == null) return; + + _nameController.text = _booking!.getCustomerName(); + _selectedServiceType = _booking!.serviceType ?? 'Jahit Baru'; + _selectedCategory = _booking!.category ?? 'Bawahan'; + + // Set harga jika sudah ada + if (_booking?.totalPrice != null && _booking!.totalPrice!.isNotEmpty) { + // Bersihkan format harga (hapus Rp, titik, koma, dsb) + _priceController.text = _cleanRupiah(_booking!.totalPrice!); + print('DEBUG: Harga dibersihkan: ${_priceController.text}'); + } else { + _priceController.text = ''; + } + + // Set ukuran berdasarkan kategori yang dipilih + if (_measurementsByCategory.containsKey(_selectedCategory)) { + for (final measurement in _measurementsByCategory[_selectedCategory]!) { + // Inisialisasi dengan nilai kosong atau nilai yang tersimpan jika ada + if (_booking?.measurements != null) { + try { + // Cara 1: Coba parse JSON string menjadi Map + Map measurementsMap; + try { + measurementsMap = jsonDecode(_booking!.measurements!); + } catch (jsonError) { + print('DEBUG: JSON parse error: $jsonError'); + + // Cara 2: Format tidak standard, coba parse manual + measurementsMap = _parseNonStandardJson(_booking!.measurements!); + } + + // Ambil nilai pengukuran + final key = measurement.toLowerCase().replaceAll(' ', '_'); + _measurementControllers[measurement]?.text = + measurementsMap[key]?.toString() ?? ''; + + // Debug output + print('DEBUG: Measurement $measurement = ${_measurementControllers[measurement]?.text}'); + + // Set catatan tambahan jika ada + if (measurementsMap.containsKey('catatan_tambahan')) { + _additionalNotesController.text = + measurementsMap['catatan_tambahan'] ?? ''; + } + } catch (e) { + // Jika parsing gagal, gunakan string kosong + print('ERROR: Gagal parsing measurements: $e'); + _measurementControllers[measurement]?.text = ''; + } + } else { + _measurementControllers[measurement]?.text = ''; + } + } + } + + // Jika ada catatan perbaikan + if (_booking?.repairNotes != null && _booking!.repairNotes!.isNotEmpty) { + _repairNotesController.text = _booking!.repairNotes!; + } else if (_booking?.notes != null && _booking!.notes!.isNotEmpty) { + _repairNotesController.text = _booking!.notes!; + } + + // Jika ada foto kerusakan + if (_booking?.repairPhoto != null && _booking!.repairPhoto!.isNotEmpty) { + _damagePhotoPath = _booking!.repairPhoto; + _damagePhotoFile = null; // Reset _damagePhotoFile karena foto dari API + } + } + + // Tambahkan fungsi untuk parsing JSON non-standard + Map _parseNonStandardJson(String input) { + print('DEBUG: Parsing non-standard JSON: $input'); + + // Hapus kurung kurawal pembuka dan penutup + String content = input.trim(); + if (content.startsWith('{')) content = content.substring(1); + if (content.endsWith('}')) content = content.substring(0, content.length - 1); + + Map result = {}; + + // Split berdasarkan koma, tapi berhati-hati dengan koma dalam string + bool inString = false; + int lastSplit = 0; + List parts = []; + + for (int i = 0; i < content.length; i++) { + if (content[i] == '"' || content[i] == "'") { + inString = !inString; + } else if (content[i] == ',' && !inString) { + parts.add(content.substring(lastSplit, i).trim()); + lastSplit = i + 1; + } + } + + // Tambahkan bagian terakhir + if (lastSplit < content.length) { + parts.add(content.substring(lastSplit).trim()); + } + + // Parse setiap bagian key: value + for (String part in parts) { + print('DEBUG: Parsing part: $part'); + int colonIndex = part.indexOf(':'); + if (colonIndex > 0) { + String key = part.substring(0, colonIndex).trim(); + String value = part.substring(colonIndex + 1).trim(); + + // Bersihkan key dari tanda kutip + if (key.startsWith('"') && key.endsWith('"')) { + key = key.substring(1, key.length - 1); + } else if (key.startsWith("'") && key.endsWith("'")) { + key = key.substring(1, key.length - 1); + } + + // Bersihkan value dari tanda kutip + if (value.startsWith('"') && value.endsWith('"')) { + value = value.substring(1, value.length - 1); + } else if (value.startsWith("'") && value.endsWith("'")) { + value = value.substring(1, value.length - 1); + } + + result[key] = value; + print('DEBUG: Parsed key: "$key", value: "$value"'); + } + } + + print('DEBUG: Parsing result: $result'); + return result; + } + + void _updateSelectedCategory(String category) { + setState(() { + _selectedCategory = category; + _selectedMeasurements = Map.fromEntries( + (_measurementsByCategory[category] ?? []) + .map((measurement) => MapEntry(measurement, true))); + }); + } + + Future _acceptBooking() async { + if (!mounted || _booking == null) return; + + setState(() { + _isProcessing = true; + }); + + try { + final result = await ApiService.acceptBooking(_booking!.id); + + if (!mounted) return; + + setState(() { + _isProcessing = false; + }); + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + // Kembali ke halaman sebelumnya + Navigator.pop(context, true); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (!mounted) return; + + setState(() { + _isProcessing = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + Future _showRejectDialog() async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Tolak Pesanan'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text('Masukkan alasan penolakan pesanan:'), + const SizedBox(height: 16), + TextField( + controller: _rejectionReasonController, + decoration: const InputDecoration( + hintText: 'Alasan penolakan', + border: OutlineInputBorder(), + ), + maxLines: 3, + ), + ], + ), + ), + actions: [ + TextButton( + child: const Text('Batal'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: const Text('Tolak Pesanan'), + onPressed: () { + Navigator.of(context).pop(); + _rejectBooking(_rejectionReasonController.text); + }, + ), + ], + ); + }, + ); + } + + Future _rejectBooking(String reason) async { + if (!mounted || _booking == null) return; + + if (reason.trim().isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Alasan penolakan harus diisi'), + backgroundColor: Colors.red, + ), + ); + return; + } + + setState(() { + _isProcessing = true; + }); + + try { + final result = await ApiService.rejectBooking(_booking!.id, reason); + + if (!mounted) return; + + setState(() { + _isProcessing = false; + }); + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + // Kembali ke halaman sebelumnya + Navigator.pop(context, true); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (!mounted) return; + + setState(() { + _isProcessing = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // Tambahkan fungsi untuk mendapatkan URL foto lengkap + String _getFullImageUrl(String? photoPath) { + if (photoPath == null || photoPath.isEmpty) { + return ''; + } + + // Jika sudah URL lengkap, kembalikan apa adanya + if (photoPath.startsWith('http')) { + return photoPath; + } + + // Pastikan photo path memiliki format yang benar + if (photoPath.startsWith('design_photos/')) { + // URL untuk design_photos seharusnya menggunakan storage/ + return '${ApiService.imageBaseUrl}/storage/$photoPath'; + } else if (!photoPath.startsWith('/')) { + return '${ApiService.imageBaseUrl}/storage/$photoPath'; + } + + // Format lainnya + return ApiService.getFullImageUrl(photoPath); + } + + // Modifikasi fungsi _buildImagePlaceholder untuk menampilkan foto dengan benar + Widget _buildImagePlaceholder() { + // Cek apakah ada design photo + if (_booking?.designPhoto != null && _booking!.designPhoto!.isNotEmpty) { + final String imageUrl = _getFullImageUrl(_booking!.designPhoto); + print('DEBUG: URL Foto Desain: $imageUrl'); + + return Container( + width: double.infinity, + height: 200, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + imageUrl, + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + print('ERROR: Gagal memuat gambar desain: $error'); + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.broken_image, + size: 50, color: Colors.grey), + const SizedBox(height: 8), + Text( + 'Gagal memuat gambar\n$error', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 12, + ), + ), + ], + ), + ); + }, + ), + ), + ); + } else { + // Tampilan jika tidak ada foto desain + return Container( + width: double.infinity, + height: 200, + decoration: BoxDecoration( + color: Colors.grey.shade200, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade300), + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.image_not_supported, + size: 50, color: Colors.grey.shade400), + const SizedBox(height: 8), + Text( + 'Tidak ada foto desain', + style: TextStyle(color: Colors.grey.shade600), + ), + ], + ), + ), + ); + } + } + + // Fungsi untuk menyimpan data pesanan + Future _saveOrderData() async { + if (!mounted || _booking == null) return; + + setState(() { + _isSaving = true; + }); + + try { + // Berdasarkan jenis layanan, gunakan API yang sesuai + if (_selectedServiceType == 'Jahit Baru') { + // Validasi data ukuran + bool hasMeasurements = false; + if (_measurementsByCategory.containsKey(_selectedCategory)) { + for (final measurement + in _measurementsByCategory[_selectedCategory]!) { + if (_measurementControllers[measurement]?.text.trim().isNotEmpty ?? + false) { + hasMeasurements = true; + break; + } + } + } + + if (!hasMeasurements) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mohon isi minimal satu ukuran'), + backgroundColor: Colors.orange, + ), + ); + setState(() { + _isSaving = false; + }); + return; + } + + await _updateMeasurements(); + } else if (_selectedServiceType == 'Perbaikan') { + // Validasi catatan perbaikan + if (_repairNotesController.text.trim().isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mohon isi catatan perbaikan'), + backgroundColor: Colors.orange, + ), + ); + setState(() { + _isSaving = false; + }); + return; + } + + await _updateRepairDetails(); + } + + if (!mounted) return; + + setState(() { + _isSaving = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Data pesanan berhasil disimpan'), + backgroundColor: Colors.green, + ), + ); + + // Reload data + _fetchBookingDetail(); + } catch (e) { + if (!mounted) return; + + setState(() { + _isSaving = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // Update ukuran untuk jahit baru + Future _updateMeasurements() async { + print('DEBUG: Memperbarui ukuran untuk kategori: $_selectedCategory'); + try { + if (!_measurementsByCategory.containsKey(_selectedCategory)) { + return; + } + + // Kumpulkan data ukuran + Map measurements = {}; + bool hasValidMeasurement = false; + + for (final measurement in _measurementsByCategory[_selectedCategory]!) { + final value = _measurementControllers[measurement]?.text.trim() ?? ''; + if (value.isNotEmpty) { + final key = measurement.toLowerCase().replaceAll(' ', '_'); + measurements[key] = value; + hasValidMeasurement = true; + print('DEBUG: Ukuran $key = $value'); + } + } + + // Tambahkan catatan tambahan jika diperlukan + final additionalNotes = _additionalNotesController.text.trim(); + if (additionalNotes.isNotEmpty) { + measurements['catatan_tambahan'] = additionalNotes; + print('DEBUG: Catatan tambahan: $additionalNotes'); + } + + if (!hasValidMeasurement) { + print('DEBUG: Tidak ada ukuran yang diisi'); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mohon isi minimal satu ukuran'), + backgroundColor: Colors.orange, + ), + ); + return; + } + + final token = await ApiService.getToken(); + if (token == null) { + throw Exception('Token tidak ditemukan. Silakan login kembali.'); + } + + print('DEBUG: Mengirim data ukuran: $measurements'); + + // Konversi ke JSON String yang valid + final measurementsJson = jsonEncode(measurements); + print('DEBUG: JSON data ukuran: $measurementsJson'); + + final response = await http.post( + Uri.parse( + '${ApiService.baseUrl}/bookings/${_booking!.id}/measurements'), + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: jsonEncode({ + 'measurements': measurements, + }), + ); + + print( + 'DEBUG: Update measurements response status: ${response.statusCode}'); + print('DEBUG: Update measurements response body: ${response.body}'); + + if (response.statusCode != 200) { + final responseData = jsonDecode(response.body); + throw Exception(responseData['message'] ?? 'Gagal memperbarui ukuran'); + } + + // Update UI feedback + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Ukuran berhasil disimpan'), + backgroundColor: Colors.green, + ), + ); + + // Refresh data dari server setelah update + _fetchBookingDetail(); + + } catch (e) { + print('ERROR: Gagal update ukuran: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal memperbarui ukuran: $e'), + backgroundColor: Colors.red, + ), + ); + rethrow; + } + } + + // Update detail perbaikan untuk layanan perbaikan + Future _updateRepairDetails() async { + print( + 'DEBUG: Memperbarui detail perbaikan. Jenis: $_selectedCategory, Ada Foto: ${_damagePhotoFile != null}'); + try { + final token = await ApiService.getToken(); + if (token == null) { + throw Exception('Token tidak ditemukan. Silakan login kembali.'); + } + + // Buat request multipart untuk mengirim file + var request = http.MultipartRequest( + 'POST', + Uri.parse('${ApiService.baseUrl}/bookings/${_booking!.id}/repair'), + ); + + // Tambahkan headers + request.headers.addAll({ + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }); + + // Siapkan data perbaikan dalam format JSON string + Map repairDetails = { + 'jenis_perbaikan': _selectedCategory, + 'bagian': _selectedCategory, + }; + + // Tambahkan field sebagai JSON string + request.fields['repair_details'] = jsonEncode(repairDetails); + request.fields['repair_notes'] = _repairNotesController.text.trim(); + + // Tambahkan foto jika ada + if (_damagePhotoFile != null) { + // Jika ada file lokal yang baru diupload + request.files.add( + await http.MultipartFile.fromPath( + 'repair_photo', + _damagePhotoFile!.path, + ), + ); + } else if (_damagePhotoPath != null && + _damagePhotoPath!.isNotEmpty && + !_damagePhotoPath!.startsWith('http')) { + // Jika _damagePhotoPath adalah path file lokal (bukan URL) + request.fields['repair_photo'] = _damagePhotoPath!; + } + // Jika _damagePhotoPath adalah URL dan tidak ada file baru, tidak perlu mengirim foto + + // Kirim request + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + + print( + 'DEBUG: Update repair details response status: ${response.statusCode}'); + print('DEBUG: Update repair details response body: ${response.body}'); + + if (response.statusCode != 200) { + final responseData = jsonDecode(response.body); + throw Exception( + responseData['message'] ?? 'Gagal memperbarui detail perbaikan'); + } + } catch (e) { + print('ERROR: Gagal update detail perbaikan: $e'); + rethrow; + } + } + + // Fungsi untuk mengunggah foto kerusakan + Future _uploadDamagePhoto() async { + setState(() { + _isUploadingPhoto = true; + }); + + try { + // Tampilkan dialog pilihan sumber foto + final imageSource = await _showImageSourceDialog(); + + if (imageSource == null) { + setState(() { + _isUploadingPhoto = false; + }); + return; + } + + // Pilih foto dari sumber yang dipilih + final pickedFile = await _pickImage(imageSource); + + if (pickedFile != null) { + setState(() { + _damagePhotoFile = pickedFile; + _damagePhotoPath = pickedFile.path; + _isUploadingPhoto = false; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Foto kerusakan berhasil dipilih'), + backgroundColor: Colors.green, + ), + ); + }); + } else { + setState(() { + _isUploadingPhoto = false; + }); + } + } catch (e) { + if (!mounted) return; + + setState(() { + _isUploadingPhoto = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // Dialog untuk memilih sumber gambar (galeri atau kamera) + Future _showImageSourceDialog() async { + return await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Pilih Sumber Foto'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.photo_library), + title: const Text('Galeri'), + onTap: () => Navigator.pop(context, ImageSource.gallery), + ), + ListTile( + leading: const Icon(Icons.camera_alt), + title: const Text('Kamera'), + onTap: () => Navigator.pop(context, ImageSource.camera), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Batal'), + ), + ], + ), + ); + } + + // Fungsi untuk memilih gambar dari galeri atau kamera + Future _pickImage(ImageSource source) async { + try { + final picker = ImagePicker(); + final pickedFile = await picker.pickImage( + source: source, + imageQuality: 80, // Mengurangi ukuran file jika terlalu besar + ); + + if (pickedFile != null) { + return File(pickedFile.path); + } + return null; + } catch (e) { + print('ERROR: Gagal memilih gambar: $e'); + // Tampilkan pesan error jika diperlukan + return null; + } + } + + // Fungsi untuk memilih gambar dari galeri (deprecated, digantikan oleh _pickImage) + Future _pickImageFromGallery() async { + return _pickImage(ImageSource.gallery); + } + + // Fungsi untuk membangun form input ukuran + Widget _buildMeasurementInputs() { + if (!_measurementsByCategory.containsKey(_selectedCategory)) { + return const SizedBox.shrink(); + } + + final measurements = _measurementsByCategory[_selectedCategory]!; + + // Cek apakah ada ukuran yang sudah terisi + bool hasMeasurements = false; + for (String measurement in measurements) { + if (_measurementControllers[measurement]?.text.isNotEmpty ?? false) { + hasMeasurements = true; + break; + } + } + + // Cek apakah status sudah selesai (hanya tampilkan, tidak bisa edit) + final bool isCompleted = _booking?.status.toLowerCase() == 'selesai'; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _buildSectionTitle('Ukuran $_selectedCategory'), + if (hasMeasurements) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.green.shade100, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + 'Ukuran terisi', + style: TextStyle( + fontSize: 12, + color: Colors.green.shade800, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + if (!hasMeasurements && !isCompleted) + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + margin: const EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: Colors.amber.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.amber.shade200), + ), + child: Row( + children: [ + Icon(Icons.info_outline, color: Colors.amber.shade800, size: 20), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Belum ada ukuran yang diisi. Silakan isi minimal satu ukuran.', + style: TextStyle( + fontSize: 13, + color: Colors.amber.shade900, + ), + ), + ), + ], + ), + ), + ...measurements + .map((measurement) => Padding( + padding: const EdgeInsets.only(bottom: 12), + child: _buildTextField( + measurement, + _measurementControllers[measurement]!, + enabled: !isCompleted, + keyboardType: TextInputType.number, + suffixText: 'cm', + ), + )) + , + const SizedBox(height: 16), + _buildSectionTitle('Catatan Tambahan'), + const SizedBox(height: 12), + TextField( + controller: _additionalNotesController, + enabled: !isCompleted, + maxLines: 2, + decoration: InputDecoration( + hintText: isCompleted + ? '' + : 'Catatan tambahan untuk ukuran (opsional)', + filled: true, + fillColor: Colors.white, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + ), + ), + ], + ); + } + + // Fungsi untuk membangun form input perbaikan + Widget _buildRepairInputs() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSectionTitle('Catatan Perbaikan'), + const SizedBox(height: 12), + TextField( + controller: _repairNotesController, + maxLines: 4, + decoration: InputDecoration( + hintText: 'Masukkan detail perbaikan yang dibutuhkan', + filled: true, + fillColor: Colors.white, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + ), + ), + const SizedBox(height: 20), + _buildSectionTitle('Foto Kerusakan'), + const SizedBox(height: 12), + _buildDamagePhotoUploader(), + ], + ); + } + + // Fungsi untuk membangun uploader foto kerusakan + Widget _buildDamagePhotoUploader() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (_damagePhotoPath != null && _damagePhotoPath!.isNotEmpty) + Container( + width: double.infinity, + height: 200, + margin: const EdgeInsets.only(bottom: 12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: _damagePhotoFile != null + ? Image.file( + _damagePhotoFile!, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print('ERROR: Gagal memuat file gambar lokal: $error'); + return _buildBrokenImagePlaceholder(); + }, + ) + : Image.network( + _getFullImageUrl(_damagePhotoPath), + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + print('ERROR: Gagal memuat gambar dari URL: $error'); + return _buildBrokenImagePlaceholder(); + }, + ), + ), + ), + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton.icon( + onPressed: _isUploadingPhoto ? null : _uploadDamagePhoto, + icon: _isUploadingPhoto + ? Container( + width: 24, + height: 24, + padding: const EdgeInsets.all(2.0), + child: const CircularProgressIndicator( + color: Colors.white, + strokeWidth: 3, + ), + ) + : const Icon(Icons.camera_alt), + label: Text(_damagePhotoPath == null + ? 'Upload Foto Kerusakan' + : 'Ganti Foto'), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + ], + ); + } + + // Widget placeholder untuk gambar yang gagal dimuat + Widget _buildBrokenImagePlaceholder() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.broken_image, size: 50, color: Colors.grey), + const SizedBox(height: 8), + Text( + 'Gagal memuat gambar', + style: TextStyle(color: Colors.grey.shade600), + ), + ], + ), + ); + } + + // Modifikasi fungsi _buildTextField untuk menambahkan suffixText + Widget _buildTextField( + String label, + TextEditingController controller, { + bool enabled = true, + TextInputType keyboardType = TextInputType.text, + String? prefixText, + String? suffixText, + }) { + return TextField( + controller: controller, + enabled: enabled, + keyboardType: keyboardType, + decoration: InputDecoration( + labelText: label, + filled: true, + fillColor: Colors.white, + prefixText: prefixText, + suffixText: suffixText, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + ), + ); + } + + // Method untuk update harga pesanan + Future _updatePrice() async { + if (_booking == null) return; + + if (_priceController.text.trim().isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mohon isi harga terlebih dahulu'), + backgroundColor: Colors.orange, + ), + ); + return; + } + + // Tampilkan dialog untuk input harga dan tanggal penyelesaian + // Dialog ini sudah mencakup konfirmasi, jadi tidak perlu dialog tambahan + final bool? confirmed = await _showInputPriceAndDateDialog(); + if (confirmed != true) return; + + int price; + String completionDate = _completionDateController.text; + + try { + // Bersihkan teks harga dari karakter non-angka + final String cleanedPriceText = _priceController.text.replaceAll(RegExp(r'[^0-9]'), ''); + print('DEBUG: Cleaned price text: $cleanedPriceText'); + + if (cleanedPriceText.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Harga tidak boleh kosong'), + backgroundColor: Colors.red, + ), + ); + return; + } + + // Konversi string ke int secara langsung + price = int.parse(cleanedPriceText); + + print('DEBUG: Harga final yang akan diupdate: $price'); + print('DEBUG: Tanggal penyelesaian yang akan diupdate: $completionDate'); + } catch (e) { + print('ERROR: Gagal parsing harga: $e'); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Format harga tidak valid'), + backgroundColor: Colors.red, + ), + ); + return; + } + + setState(() { + _isUpdatingPrice = true; + }); + + try { + print('DEBUG: Mengirim update harga ke API untuk booking ID: ${_booking!.id} dengan harga: $price dan tanggal selesai: $completionDate'); + final result = await ApiService.updateBookingPrice(_booking!.id, price, completionDate); + print('DEBUG: Hasil update harga: $result'); + + if (!mounted) return; + + // Refresh data dari server untuk memastikan UI diperbarui dengan benar + await _fetchBookingDetail(); + + setState(() { + _isUpdatingPrice = false; + }); + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Harga dan tanggal selesai berhasil diperbarui'), + backgroundColor: Colors.green, + ), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Gagal memperbarui harga dan tanggal selesai'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + print('ERROR: Gagal melakukan update harga: $e'); + if (!mounted) return; + + setState(() { + _isUpdatingPrice = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // Dialog untuk menginput harga dan tanggal penyelesaian + Future _showInputPriceAndDateDialog() async { + return await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) { + return AlertDialog( + title: const Text('Penetapan Harga dan Tanggal Selesai'), + content: SingleChildScrollView( + child: ListBody( + children: [ + const Text('Masukkan harga dan tanggal penyelesaian pesanan:'), + const SizedBox(height: 16), + + // Input harga + TextField( + controller: _priceController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + labelText: 'Harga (Rp)', + border: OutlineInputBorder(), + prefixIcon: Icon(Icons.monetization_on), + hintText: 'Contoh: 150000', + ), + onChanged: (value) { + if (value.isNotEmpty) { + // Format harga dengan pemisah ribuan saat pengguna mengetik + final cleanValue = value.replaceAll(RegExp(r'[^0-9]'), ''); + if (cleanValue.isNotEmpty) { + final number = int.parse(cleanValue); + final formatted = _formatRupiah(number.toString()); + + // Hindari infinite loop dengan memeriksa apakah nilai berubah + if (formatted != value) { + _priceController.value = TextEditingValue( + text: formatted, + selection: TextSelection.collapsed(offset: formatted.length), + ); + } + } + } + }, + ), + + const SizedBox(height: 16), + + // Input tanggal penyelesaian + GestureDetector( + onTap: () => _selectCompletionDate(dialogContext), + child: AbsorbPointer( + child: TextField( + controller: _completionDateController, + decoration: const InputDecoration( + labelText: 'Tanggal Penyelesaian', + border: OutlineInputBorder(), + prefixIcon: Icon(Icons.calendar_today), + hintText: 'YYYY-MM-DD', + ), + ), + ), + ), + const SizedBox(height: 8), + const Text( + 'Pilih tanggal ketika pesanan diperkirakan selesai', + style: TextStyle( + color: Colors.grey, + fontSize: 12, + ), + ), + ], + ), + ), + actions: [ + TextButton( + child: const Text('Batal'), + onPressed: () { + Navigator.of(dialogContext).pop(false); + }, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + ), + child: const Text('Simpan', style: TextStyle(color: Colors.white)), + onPressed: () { + Navigator.of(dialogContext).pop(true); + }, + ), + ], + ); + }, + ); + } + + // Method untuk upload foto hasil jahitan + Future _uploadCompletionPhoto() async { + setState(() { + _isUploadingCompletionPhoto = true; + }); + + try { + // Tampilkan dialog pilihan sumber foto + final imageSource = await _showImageSourceDialog(); + + if (imageSource == null) { + setState(() { + _isUploadingCompletionPhoto = false; + }); + return; + } + + // Pilih foto dari sumber yang dipilih + final pickedFile = await _pickImage(imageSource); + + if (pickedFile != null) { + setState(() { + _completionPhotoFile = pickedFile; + _completionPhotoPath = pickedFile.path; + _isUploadingCompletionPhoto = false; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Foto hasil jahitan berhasil dipilih'), + backgroundColor: Colors.green, + ), + ); + }); + } else { + setState(() { + _isUploadingCompletionPhoto = false; + }); + } + } catch (e) { + if (!mounted) return; + + setState(() { + _isUploadingCompletionPhoto = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // Method untuk menyelesaikan pesanan + Future _completeBooking() async { + if (!mounted || _booking == null) return; + + if (_completionNotesController.text.trim().isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mohon isi catatan penyelesaian'), + backgroundColor: Colors.orange, + ), + ); + return; + } + + if (_completionPhotoFile == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mohon pilih foto hasil jahitan'), + backgroundColor: Colors.orange, + ), + ); + return; + } + + setState(() => _isCompletingOrder = true); + + try { + final result = await context.read().completeBooking( + widget.booking.id, + _completionNotesController.text.trim(), + _completionPhotoFile!.path, + _selectedPickupDate, + ); + + if (!mounted) return; + + setState(() { + _isCompletingOrder = false; + }); + + if (result['success']) { + // Update data booking jika ada data terbaru + if (result['booking'] != null) { + setState(() { + _booking = BookingModel.fromJson(result['booking']); + _fetchBookingDetail(); // Refresh data + }); + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Pesanan berhasil diselesaikan'), + backgroundColor: Colors.green, + ), + ); + + // Kembali ke halaman sebelumnya setelah berhasil + Future.delayed(const Duration(seconds: 2), () { + if (mounted) { + Navigator.pop(context, true); + } + }); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Gagal menyelesaikan pesanan'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (!mounted) return; + + setState(() { + _isCompletingOrder = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // Tambahkan method untuk memilih tanggal + Future _selectPickupDate(BuildContext context) async { + try { + final DateTime now = DateTime.now(); + DateTime initialDate = now.add(const Duration(days: 1)); + + if (_selectedPickupDate != null && _selectedPickupDate!.isNotEmpty) { + try { + initialDate = DateTime.parse(_selectedPickupDate!); + } catch (e) { + print('ERROR: Gagal parsing tanggal: $e'); + } + } + + final DateTime? picked = await showDatePicker( + context: context, + initialDate: initialDate, + firstDate: now, + lastDate: now.add(const Duration(days: 90)), + builder: (context, child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: const ColorScheme.light( + primary: Color(0xFF1A2552), + onPrimary: Colors.white, + onSurface: Color(0xFF1A2552), + ), + ), + child: child!, + ); + }, + ); + + if (picked != null) { + setState(() { + _selectedPickupDate = picked.toIso8601String(); + _pickupDateController.text = + "${picked.day.toString().padLeft(2, '0')}/${picked.month.toString().padLeft(2, '0')}/${picked.year}"; + }); + } + } catch (e) { + print('ERROR: Gagal memilih tanggal: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan saat memilih tanggal: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // Method untuk menyelesaikan pembayaran + Future _completePayment() async { + if (!mounted || _booking == null) return; + + // Validasi input tanggal + if (_pickupDateController.text.trim().isEmpty || + _selectedPickupDate == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Mohon pilih tanggal pengambilan terlebih dahulu'), + backgroundColor: Colors.orange, + ), + ); + return; + } + + setState(() { + _isCompletingPayment = true; + }); + + try { + final result = await ApiService.completePayment( + _booking!.id, + _selectedPickupDate!, + ); + + if (!mounted) return; + + setState(() { + _isCompletingPayment = false; + }); + + if (result['success']) { + // Update data booking jika ada data terbaru + if (result['booking'] != null) { + setState(() { + _booking = BookingModel.fromJson(result['booking']); + _fetchBookingDetail(); // Refresh data + }); + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text(result['message'] ?? 'Pembayaran berhasil dikonfirmasi'), + backgroundColor: Colors.green, + ), + ); + + // Kembali ke halaman sebelumnya setelah berhasil + Future.delayed(const Duration(seconds: 2), () { + if (mounted) { + Navigator.pop(context, true); + } + }); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text(result['message'] ?? 'Gagal mengkonfirmasi pembayaran'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (!mounted) return; + + setState(() { + _isCompletingPayment = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + + // UI untuk form penyelesaian pesanan + Widget _buildCompletionForm() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSectionTitle('Penyelesaian Pesanan'), + const SizedBox(height: 12), + + // Form input catatan penyelesaian + TextField( + controller: _completionNotesController, + maxLines: 3, + decoration: InputDecoration( + labelText: 'Catatan Penyelesaian', + hintText: 'Tulis catatan penyelesaian pesanan...', + filled: true, + fillColor: Colors.white, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + ), + ), + + const SizedBox(height: 16), + + // Upload foto hasil jahitan + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Foto Hasil Jahitan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + + // Preview foto jika sudah dipilih + if (_completionPhotoFile != null) + Container( + width: double.infinity, + height: 200, + margin: const EdgeInsets.only(bottom: 12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + _completionPhotoFile!, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print('ERROR: Gagal memuat gambar: $error'); + return _buildBrokenImagePlaceholder(); + }, + ), + ), + ), + + // Tombol upload foto + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton.icon( + onPressed: + _isUploadingCompletionPhoto ? null : _uploadCompletionPhoto, + icon: _isUploadingCompletionPhoto + ? Container( + width: 24, + height: 24, + padding: const EdgeInsets.all(2.0), + child: const CircularProgressIndicator( + color: Colors.white, + strokeWidth: 3, + ), + ) + : const Icon(Icons.camera_alt), + label: Text(_completionPhotoFile == null + ? 'Upload Foto Hasil Jahitan' + : 'Ganti Foto'), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + ], + ), + + const SizedBox(height: 24), + + // Tombol selesaikan pesanan + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: _isCompletingOrder ? null : _completeBooking, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: _isCompletingOrder + ? const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 3, + ), + ) + : const Text( + 'Selesaikan Pesanan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ); + } + + // UI untuk form konfirmasi pembayaran + Widget _buildPaymentConfirmationForm() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSectionTitle('Konfirmasi Pembayaran'), + const SizedBox(height: 12), + + // Deskripsi form + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.info_outline, + color: Colors.blue.shade700, size: 20), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Konfirmasi Pembayaran COD', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.blue.shade700, + fontSize: 14, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + 'Dengan mengonfirmasi pembayaran, Anda menyatakan bahwa pelanggan telah melunasi pembayaran Cash on Delivery (COD) dan mengatur tanggal pengambilan.', + style: TextStyle( + color: Colors.blue.shade800, + fontSize: 12, + ), + ), + ], + ), + ), + + const SizedBox(height: 20), + + // Form input tanggal pengambilan + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Tanggal Pengambilan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + InkWell( + onTap: () => _selectPickupDate(context), + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + color: Colors.white, + ), + child: Row( + children: [ + Expanded( + child: Text( + _pickupDateController.text.isEmpty + ? 'Pilih tanggal pengambilan' + : _pickupDateController.text, + style: TextStyle( + color: _pickupDateController.text.isEmpty + ? Colors.grey.shade500 + : Colors.black, + ), + ), + ), + Icon(Icons.calendar_month, color: Colors.grey.shade600), + ], + ), + ), + ), + ], + ), + + const SizedBox(height: 24), + + // Tombol konfirmasi pembayaran + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: _isCompletingPayment ? null : _completePayment, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: _isCompletingPayment + ? const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 3, + ), + ) + : const Text( + 'Konfirmasi Pembayaran COD', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ); + } + + // Di dalam class _OrderDetailPageState, tambahkan helper function untuk mendapatkan status teks pembayaran + String _getPaymentStatusText() { + if (_booking == null) return '-'; + + // Periksa properti payment_status (pastikan model memiliki properti ini) + final String paymentStatus = (_booking!.paymentStatus ?? '').toLowerCase(); + + switch (paymentStatus) { + case 'paid': + return 'Lunas'; + case 'partial': + return 'Sebagian'; + case 'unpaid': + return 'Belum Bayar'; + default: + return paymentStatus.isNotEmpty ? paymentStatus : 'Belum Bayar'; + } + } + + // Tambahkan method untuk membangun badge status pembayaran + Widget _buildPaymentStatusBadge() { + if (_booking == null) return const SizedBox.shrink(); + + final String paymentStatus = (_booking!.paymentStatus ?? '').toLowerCase(); + Color badgeColor; + IconData badgeIcon; + + switch (paymentStatus) { + case 'paid': + badgeColor = + const Color(0xFF34A853); // Hijau Google yang lebih profesional + badgeIcon = Icons.check_circle; + break; + case 'partial': + badgeColor = const Color(0xFFFBBC05); // Kuning Google + badgeIcon = Icons.monetization_on; + break; + default: + badgeColor = const Color(0xFF9AA0A6); // Abu-abu Google + badgeIcon = Icons.money_off; + break; + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: badgeColor.withOpacity(0.15), + borderRadius: BorderRadius.circular(16), + border: Border.all(color: badgeColor.withOpacity(0.5), width: 1), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(badgeIcon, color: badgeColor, size: 14), + const SizedBox(width: 4), + Text( + _getPaymentStatusText(), + style: TextStyle( + color: badgeColor, + fontWeight: FontWeight.w600, + fontSize: 12, + ), + ), + ], + ), + ); + } + + // Revisi tampilan info pembayaran untuk gaya yang lebih modern + Widget _buildPaymentInfoCard() { + if (_booking == null) return const SizedBox.shrink(); + + final String paymentStatus = (_booking!.paymentStatus ?? '').toLowerCase(); + final bool isPaid = paymentStatus == 'paid'; + final Color themeColor = + isPaid ? const Color(0xFF34A853) : const Color(0xFF1A2552); + + // Format harga dengan benar + String formattedPrice = 'Belum ditetapkan'; + int basePrice = 0; + + if (_booking!.totalPrice != null && _booking!.totalPrice!.isNotEmpty) { + // Log untuk debugging + print('DEBUG: Original totalPrice dari booking: "${_booking!.totalPrice}"'); + + // Untuk menghindari masalah dengan titik desimal, pastikan kita mengambil nilai yang benar + String priceToFormat = _booking!.totalPrice!; + + // Jika berformat desimal (mis. 50000.00), hanya ambil bagian integer + if (priceToFormat.contains('.')) { + priceToFormat = priceToFormat.split('.')[0]; + print('DEBUG: Mengambil bagian integer saja: "$priceToFormat"'); + } + + String cleanPrice = _cleanRupiah(priceToFormat); + print('DEBUG: totalPrice setelah dibersihkan: "$cleanPrice"'); + + // Parse ke integer + basePrice = int.tryParse(cleanPrice) ?? 0; + + // Pastikan nilai dalam format yang benar (hindari pembersihan ganda) + formattedPrice = _formatRupiah(cleanPrice); + print('DEBUG: Harga final yang ditampilkan: "$formattedPrice"'); + } + + // Cek metode pembayaran + final bool isCod = (_booking!.paymentMethod?.toLowerCase() == 'cod' || + _booking!.paymentMethod?.toLowerCase() == 'cash_on_delivery'); + + // Biaya tambahan - 0 jika COD + final int paymentServiceFee = isCod ? 0 : 4000; + // final int tailorServiceFee = isCod ? 0 : 1000; + final int totalPrice = basePrice + paymentServiceFee; + + return Container( + margin: const EdgeInsets.only(bottom: 20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + spreadRadius: 0, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header dengan status pembayaran yang lebih modern + Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: isPaid ? const Color(0xFFEDF7ED) : Colors.white, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(12), + topRight: Radius.circular(12), + ), + border: Border( + bottom: BorderSide( + color: + isPaid ? const Color(0xFFCEEDCE) : Colors.grey.shade200, + width: 1, + ), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Informasi Pembayaran', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: isPaid + ? const Color(0xFF1E8E3E) + : const Color(0xFF1A2552), + ), + ), + if (isPaid) + Container( + padding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: const Color(0xFF34A853), + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: const Color(0xFF34A853).withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.check, color: Colors.white, size: 14), + SizedBox(width: 4), + Text( + 'Lunas', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ], + ), + ), + // Tampilkan badge COD jika metode pembayaran COD + if (isCod) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.orange.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.orange.shade200), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.monetization_on, size: 14, color: Colors.orange.shade700), + const SizedBox(width: 4), + Text( + 'COD', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Colors.orange.shade700, + ), + ), + ], + ), + ), + ], + ), + ), + + // Isi dengan informasi pembayaran detail + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Rincian biaya + if (basePrice > 0) ...[ + // Biaya Jahit + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Biaya Jahit', + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + Text( + 'Rp $formattedPrice', + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 14, + color: Colors.black, + ), + ), + ], + ), + const SizedBox(height: 8), + + // Hanya tampilkan biaya layanan jika bukan COD + if (!isCod) ...[ + // Biaya Layanan Payment + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Biaya Layanan Payment', + style: TextStyle( + color: Colors.grey.shade700, + fontSize: 14, + ), + ), + Text( + 'Rp ${_formatRupiah(paymentServiceFee.toString())}', + style: const TextStyle( + fontSize: 14, + color: Colors.black, + ), + ), + ], + ), + const SizedBox(height: 8), + + // Biaya Layanan Tailor + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Text( + // 'Biaya Layanan Tailor', + // style: TextStyle( + // color: Colors.grey.shade700, + // fontSize: 14, + // ), + // ), + // Text( + // 'Rp ${_formatRupiah(tailorServiceFee.toString())}', + // style: const TextStyle( + // fontSize: 14, + // color: Colors.black, + // ), + // ), + // ], + // ), + ] else ...[ + // Pesan penjelasan biaya COD + Padding( + padding: const EdgeInsets.only(bottom: 12, top: 4), + child: Text( + "Tidak ada biaya layanan tambahan untuk metode COD", + style: TextStyle( + fontSize: 13, + fontStyle: FontStyle.italic, + color: Colors.grey.shade600, + ), + ), + ), + ], + + const SizedBox(height: 12), + const Divider(), + const SizedBox(height: 12), + + // Total Pembayaran + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Total Pembayaran', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: Color(0xFF1A2552), + ), + ), + Text( + 'Rp ${_formatRupiah(totalPrice.toString())}', + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: Colors.black, + ), + ), + ], + ), + ] else ...[ + // Jika tidak ada harga (belum ditetapkan) + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Row( + children: [ + Icon(Icons.info_outline, color: Colors.blue.shade700, size: 18), + const SizedBox(width: 10), + Expanded( + child: Text( + 'Harga belum ditetapkan', + style: TextStyle( + color: Colors.blue.shade700, + fontSize: 14, + ), + ), + ), + ], + ), + ), + ], + + // Tampilkan tanggal pengambilan dengan ikon kalender + if (_booking?.pickupDate != null && + _booking!.pickupDate!.isNotEmpty) ...[ + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Icon(Icons.event_available, + color: Colors.blue.shade700, size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Tanggal Pengambilan', + style: TextStyle( + color: Colors.blue.shade700, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 2), + Text( + _formatPickupDate(_booking!.pickupDate!), + style: TextStyle( + color: Colors.blue.shade900, + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ], + ), + ), + ], + ), + ); + } + + // Helper untuk memformat tanggal pengambilan + String _formatPickupDate(String isoDate) { + try { + // Parse tanggal dari format ISO + final DateTime date = DateTime.parse(isoDate); + // Format menjadi dd/MM/yyyy + return "${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year}"; + } catch (e) { + print('ERROR: Gagal memformat tanggal: $e'); + return isoDate; // Kembalikan format asli jika gagal parsing + } + } + + // Add this new widget to build rating and review card + Widget _buildRatingAndReviewCard() { + if (_booking == null || _booking?.status.toLowerCase() != 'selesai' || _booking?.rating == null) { + print('DEBUG: Rating card not shown because:'); + print('DEBUG: - Booking is null: ${_booking == null}'); + print('DEBUG: - Status is not selesai: ${_booking?.status.toLowerCase() != 'selesai'}'); + print('DEBUG: - Rating is null: ${_booking?.rating == null}'); + return const SizedBox.shrink(); + } + + // Debug print the rating data structure + print('DEBUG: Rating data: ${_booking!.rating}'); + print('DEBUG: Rating data type: ${_booking!.rating.runtimeType}'); + + // Safely access rating data + final ratingData = _booking!.rating as Map; + final ratingValue = ratingData['rating']?.toString() ?? '0.0'; + final reviewText = ratingData['review']?.toString(); + final createdAt = ratingData['created_at']?.toString(); + + print('DEBUG: Rating value: $ratingValue'); + print('DEBUG: Review text: $reviewText'); + print('DEBUG: Created at: $createdAt'); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSectionTitle('Rating & Ulasan'), + const SizedBox(height: 12), + Container( + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Rating section + Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: Colors.amber.shade100, + borderRadius: BorderRadius.circular(20), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.star, color: Colors.amber, size: 18), + const SizedBox(width: 4), + Text( + ratingValue, + style: const TextStyle( + color: Colors.amber, + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ], + ), + ), + const SizedBox(width: 12), + Text( + 'dari pelanggan', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 14, + ), + ), + ], + ), + ), + + // Divider + Divider(height: 1, color: Colors.grey.shade200), + + // Review section + if (reviewText != null && reviewText.isNotEmpty) + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Ulasan:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + Text( + reviewText, + style: const TextStyle( + fontSize: 14, + color: Colors.black87, + ), + ), + ], + ), + ), + + // Review date + if (createdAt != null) + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), + child: Text( + 'Diberikan pada ${_formatDate(createdAt)}', + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade500, + ), + ), + ), + ], + ), + ), + ], + ); + } + + // Add helper method to format date + String _formatDate(String dateStr) { + try { + final date = DateTime.parse(dateStr); + return "${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year}"; + } catch (e) { + print('ERROR: Gagal memformat tanggal: $e'); + return dateStr; + } + } + + // Widget untuk input harga dan tanggal penyelesaian yang lebih user friendly + Widget _buildPriceInput() { + return Card( + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + color: Colors.white, // Mengubah warna background menjadi putih + margin: EdgeInsets.zero, // Menghilangkan margin default dari Card + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, // Mengatur ukuran kolom agar tidak memakan ruang berlebih + children: [ + // Header dengan ikon + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF1A2552).withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.price_check, + color: Color(0xFF1A2552), + size: 20, // Mengurangi ukuran ikon + ), + ), + const SizedBox(width: 12), + const Text( + 'Informasi Harga & Penyelesaian', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + + const SizedBox(height: 16), // Mengurangi jarak + + // Input harga dengan format yang lebih baik + const Text( + 'Harga Pesanan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.grey.shade50, + border: Border.all(color: Colors.grey.shade300), + ), + child: Row( + children: [ + // Prefiks Rp + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(9), + bottomLeft: Radius.circular(9), + ), + border: Border( + right: BorderSide(color: Colors.grey.shade300), + ), + ), + child: const Text( + 'Rp', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ), + + // Input field + Expanded( + child: TextField( + controller: _priceController, + keyboardType: TextInputType.number, + style: const TextStyle(fontSize: 16), + decoration: const InputDecoration( + hintText: 'Masukkan harga pesanan', + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(horizontal: 12), + ), + onChanged: (value) { + if (value.isNotEmpty) { + final cleanValue = value.replaceAll(RegExp(r'[^0-9]'), ''); + if (cleanValue.isNotEmpty) { + final number = int.parse(cleanValue); + final formatted = _formatRupiah(number.toString()); + + // Hindari infinite loop dengan memeriksa apakah nilai berubah + if (formatted != value) { + _priceController.value = TextEditingValue( + text: formatted, + selection: TextSelection.collapsed(offset: formatted.length), + ); + } + } + } + }, + ), + ), + ], + ), + ), + + const SizedBox(height: 16), // Mengurangi jarak + + // Input tanggal penyelesaian dengan tampilan yang lebih baik + const Text( + 'Tanggal Penyelesaian', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + GestureDetector( + onTap: () => _selectCompletionDate(context), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), // Mengurangi padding vertikal + decoration: BoxDecoration( + color: Colors.grey.shade50, + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + children: [ + Icon(Icons.calendar_today, color: Colors.blue.shade700, size: 18), + const SizedBox(width: 12), + Expanded( + child: Text( + // Format tanggal ke format yang lebih mudah dibaca oleh user + _getFormattedCompletionDate(), + style: const TextStyle( + fontSize: 15, // Mengurangi ukuran font + color: Colors.black87, + ), + ), + ), + Icon( + Icons.arrow_drop_down, + color: Colors.grey.shade600, + ), + ], + ), + ), + ), + + const SizedBox(height: 10), // Mengurangi jarak + + // Info box tentang tanggal penyelesaian + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), // Mengurangi padding + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, // Memastikan ikon sejajar dengan teks di atas + children: [ + Padding( + padding: const EdgeInsets.only(top: 2), // Sesuaikan posisi ikon + child: Icon(Icons.info_outline, color: Colors.blue.shade700, size: 14), // Mengurangi ukuran ikon + ), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Tanggal ini akan ditampilkan ke pelanggan sebagai estimasi waktu penyelesaian pesanan', + style: TextStyle( + fontSize: 11, // Mengurangi ukuran font + color: Colors.blue.shade800, + ), + ), + ), + ], + ), + ), + + const SizedBox(height: 16), // Mengurangi jarak + + // Tombol update yang lebih menarik + SizedBox( + width: double.infinity, + height: 48, // Menetapkan tinggi tombol secara eksplisit + child: ElevatedButton.icon( + onPressed: _isUpdatingPrice ? null : _updatePrice, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 0), // Mengurangi padding + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + elevation: 0, // Mengurangi shadow + ), + icon: _isUpdatingPrice + ? Container( + width: 18, + height: 18, + padding: const EdgeInsets.all(0), + child: const CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ), + ) + : const Icon(Icons.check_circle_outline, size: 18), // Mengurangi ukuran ikon + label: Text( + _isUpdatingPrice ? 'Menyimpan...' : 'Simpan Harga & Tanggal', + style: const TextStyle( + fontSize: 15, // Mengurangi ukuran font + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ), + ), + ); + } + + // Method untuk mendapatkan format tanggal yang lebih user-friendly + String _getFormattedCompletionDate() { + try { + final date = DateTime.parse(_completionDateController.text); + + // Format default untuk semua tanggal (tanpa logic relatif) + return DateFormat('d MMMM yyyy').format(date); + } catch (e) { + // Jika gagal parsing, kembalikan text yang ada di controller + print('ERROR: Gagal parsing tanggal penyelesaian: $e'); + return _completionDateController.text; + } + } + + // Widget untuk menampilkan foto hasil dan catatan penyelesaian pada pesanan dengan status selesai + Widget _buildCompletionDetails() { + if (_booking?.completionPhoto == null || _booking!.completionPhoto!.isEmpty) { + return const SizedBox.shrink(); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildSectionTitle('Detail Penyelesaian Pesanan'), + const SizedBox(height: 12), + + // Tampilkan foto hasil jahitan + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Foto Hasil Jahitan', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + Container( + width: double.infinity, + height: 200, + margin: const EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + _getFullImageUrl(_booking!.completionPhoto), + fit: BoxFit.cover, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + print('ERROR: Gagal memuat gambar dari URL: $error'); + return _buildBrokenImagePlaceholder(); + }, + ), + ), + ), + ], + ), + + // Tampilkan catatan penyelesaian jika ada + if (_booking?.completionNotes != null && _booking!.completionNotes!.isNotEmpty) ...[ + Text( + 'Catatan Penyelesaian', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + margin: const EdgeInsets.only(bottom: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade300), + ), + child: Text( + _booking!.completionNotes!, + style: const TextStyle( + fontSize: 14, + color: Colors.black87, + ), + ), + ), + ], + ], + ); + } + + @override + Widget build(BuildContext context) { + if (_isLoading) { + return Scaffold( + appBar: AppBar( + title: const Text( + 'Detail Booking', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFF1A2552)), + onPressed: () => Navigator.pop(context), + ), + centerTitle: true, + backgroundColor: Colors.white, + elevation: 0, + ), + body: const Center( + child: CircularProgressIndicator(), + ), + ); + } + + if (_errorMessage.isNotEmpty) { + return Scaffold( + appBar: AppBar( + title: const Text( + 'Detail Booking', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFF1A2552)), + onPressed: () => Navigator.pop(context), + ), + centerTitle: true, + backgroundColor: Colors.white, + elevation: 0, + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + _errorMessage, + textAlign: TextAlign.center, + style: const TextStyle(color: Colors.red), + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: _fetchBookingDetail, + child: const Text('Coba Lagi'), + ), + ], + ), + ), + ); + } + + final isOrderInProcess = _booking?.status.toLowerCase() == 'diproses'; + final isNewTailoring = _selectedServiceType == 'Jahit Baru'; + final isRepair = _selectedServiceType == 'Perbaikan'; + final isCompleted = _booking?.status.toLowerCase() == 'selesai'; + + // Cek apakah pesanan sudah memiliki data lengkap untuk ditentuken harganya + final bool canSetPrice = isOrderInProcess && + ((isNewTailoring && + _booking?.measurements != null && + _booking!.measurements!.isNotEmpty) || + (isRepair && + _booking?.repairDetails != null && + _booking!.repairDetails!.isNotEmpty)); + + // Cek apakah pesanan sudah memiliki harga (untuk menyelesaikan pesanan) + final bool canComplete = isOrderInProcess && + _booking?.totalPrice != null && + _booking!.totalPrice!.isNotEmpty; + + // Cek apakah status selesai dan belum ada pickup date + final bool canConfirmPayment = + _booking?.status.toLowerCase() == 'selesai' && + (_booking?.pickupDate == null || _booking!.pickupDate!.isEmpty) && + (_booking?.paymentMethod != null && + (_booking!.paymentMethod!.toLowerCase() == 'cod' || + _booking!.paymentMethod!.toLowerCase() == 'cash_on_delivery')); + + return Scaffold( + backgroundColor: Colors.grey[50], + appBar: AppBar( + title: const Text( + 'Detail Booking', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFF1A2552)), + onPressed: () => Navigator.pop(context), + ), + centerTitle: true, + backgroundColor: Colors.white, + elevation: 1, + ), + body: _isProcessing || + _isSaving || + _isCompletingOrder || + _isCompletingPayment + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Bagian Detail Pesanan + _buildSectionTitle('Detail Pesanan'), + const SizedBox(height: 8), + _buildInfoCard([ + _buildInfoRow( + 'Tanggal', _booking?.getFormattedDate() ?? '-'), + _buildInfoRow('Waktu', _booking?.appointmentTime ?? '-'), + _buildInfoRow( + 'Status Pesanan', _booking?.getStatusText() ?? '-'), + ]), + + const SizedBox(height: 20), + + // Tampilkan info pembayaran jika pesanan sudah memiliki harga + if (_booking?.totalPrice != null && + _booking!.totalPrice!.isNotEmpty) + _buildPaymentInfoCard(), + + // Jenis Layanan dan Kategori + _buildSectionTitle('Jenis Layanan'), + const SizedBox(height: 8), + _buildTextField( + 'Jenis', + TextEditingController(text: _booking?.serviceType ?? '-'), + enabled: false, + ), + + const SizedBox(height: 16), + + _buildSectionTitle('Kategori'), + const SizedBox(height: 8), + _buildTextField( + 'Kategori', + TextEditingController(text: _booking?.category ?? '-'), + enabled: false, + ), + + const SizedBox(height: 16), + + // Detail penyelesaian untuk pesanan dengan status selesai + if (isCompleted) ...[ + _buildCompletionDetails(), + const SizedBox(height: 20), + ], + + // Jika status diproses atau selesai dan jenis layanan Jahit Baru, tampilkan input ukuran + if ((isOrderInProcess || _booking?.status.toLowerCase() == 'selesai') && isNewTailoring) ...[ + _buildMeasurementInputs(), + const SizedBox(height: 20), + ], + + // Jika status diproses dan jenis layanan Perbaikan, tampilkan input catatan dan foto kerusakan + if (isOrderInProcess && isRepair) ...[ + _buildRepairInputs(), + const SizedBox(height: 20), + ], + + // Tambahkan input harga jika pesanan sudah memiliki data lengkap + if (canSetPrice) ...[ + _buildPriceInput(), + const SizedBox(height: 20), + ], + + // Tambahkan form penyelesaian jika pesanan sudah memiliki harga + if (canComplete) ...[ + _buildCompletionForm(), + const SizedBox(height: 20), + ], + + // Tambahkan form konfirmasi pembayaran jika status selesai, belum ada pickup date dan belum paid + if (canConfirmPayment && + (_booking?.paymentStatus == null || + _booking!.paymentStatus!.toLowerCase() != + 'paid')) ...[ + _buildPaymentConfirmationForm(), + const SizedBox(height: 20), + ], + + _buildSectionTitle('Foto Pesanan Desain'), + const SizedBox(height: 8), + _buildImagePlaceholder(), + + const SizedBox(height: 24), + + // Tombol Simpan untuk status diproses + if (isOrderInProcess) + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: _saveOrderData, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text( + 'Simpan Data', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + + // Action Buttons for Reservasi status + if (_booking?.status.toLowerCase() == 'reservasi') + Column( + children: [ + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: _acceptBooking, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text( + 'Terima Booking', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + const SizedBox(height: 12), + SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + onPressed: _showRejectDialog, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.red, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: const BorderSide(color: Colors.red), + ), + ), + child: const Text( + 'Tolak Booking', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ), + + // Rating and review card moved to the bottom + if (_booking?.totalPrice != null && + _booking!.totalPrice!.isNotEmpty) ...[ + const SizedBox(height: 20), + _buildRatingAndReviewCard(), + ], + ], + ), + ), + ); + } + + Widget _buildSectionTitle(String title) { + return Text( + title, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ); + } + + Widget _buildInfoCard(List children) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(16), + child: Column( + children: [ + ...children, + + // Tambahkan kode transaksi jika tersedia + if (_booking?.transactionCode != null && _booking!.transactionCode!.isNotEmpty) ...[ + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade200), + ), + child: Row( + children: [ + Icon(Icons.receipt_long, color: Colors.blue.shade700, size: 16), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Kode Transaksi', + style: TextStyle( + color: Colors.blue.shade700, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + _booking!.transactionCode!, + style: TextStyle( + color: Colors.blue.shade900, + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + ), + ], + + // Tampilkan metode pembayaran jika tersedia + if (_booking?.paymentMethod != null && _booking!.paymentMethod!.isNotEmpty) ...[ + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.green.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.green.shade200), + ), + child: Row( + children: [ + Icon( + _getPaymentMethodIcon(_booking!.paymentMethod!), + color: Colors.green.shade700, + size: 16 + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Metode Pembayaran', + style: TextStyle( + color: Colors.green.shade700, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + _getPaymentMethodText(_booking!.paymentMethod!), + style: TextStyle( + color: Colors.green.shade900, + fontSize: 14, + ), + ), + ], + ), + ), + ], + ), + ), + ], + + // Tambahkan notes jika ada + if (_booking?.notes != null && _booking!.notes!.isNotEmpty) ...[ + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade200), + ), + child: Row( + children: [ + Icon(Icons.note, color: Colors.blue.shade700, size: 16), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Catatan Pesanan', + style: TextStyle( + color: Colors.blue.shade700, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + _booking!.notes ?? '', + style: TextStyle( + color: Colors.blue.shade900, + fontSize: 14, + ), + ), + ], + ), + ), + ], + ), + ), + ], + // Tambahkan alasan penolakan jika status dibatalkan + if (_booking?.status.toLowerCase() == 'dibatalkan' && + _booking?.rejectionReason != null && + _booking!.rejectionReason!.isNotEmpty) ...[ + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.red.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.red.shade200), + ), + child: Row( + children: [ + Icon(Icons.cancel, color: Colors.red.shade700, size: 16), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Alasan Penolakan', + style: TextStyle( + color: Colors.red.shade700, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + _booking!.rejectionReason!, + style: TextStyle( + color: Colors.red.shade900, + fontSize: 14, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ], + ), + ); + } + + // Helper untuk mendapatkan ikon metode pembayaran + IconData _getPaymentMethodIcon(String method) { + switch (method.toLowerCase()) { + case 'transfer_bank': + return Icons.account_balance; + case 'cod': + case 'cash_on_delivery': + return Icons.monetization_on; + default: + return Icons.payment; + } + } + + // Helper untuk mendapatkan teks metode pembayaran + String _getPaymentMethodText(String method) { + switch (method.toLowerCase()) { + case 'transfer_bank': + return 'Transfer Bank'; + case 'cod': + case 'cash_on_delivery': + return 'Cash on Delivery (COD)'; + default: + return method; + } + } + + Widget _buildInfoRow(String label, String value) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + children: [ + SizedBox( + width: 140, + child: Text( + label, + style: TextStyle( + fontSize: 14, + color: Colors.grey[600], + ), + ), + ), + const Text(':'), + const SizedBox(width: 8), + Expanded( + child: Text( + value, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + ); + } + + @override + void dispose() { + _nameController.dispose(); + _dateController.dispose(); + _rejectionReasonController.dispose(); + _repairNotesController.dispose(); + _additionalNotesController.dispose(); + _priceController.dispose(); + _completionNotesController.dispose(); + _pickupDateController.dispose(); + _completionDateController.dispose(); // Tambahkan dispose untuk controller baru + + // Dispose semua measurement controllers + for (final controller in _measurementControllers.values) { + controller.dispose(); + } + + super.dispose(); + } + + // Method untuk konfirmasi harga yang sangat besar + Future _showPriceConfirmationDialog(int price) async { + // Format harga dengan pemisah ribuan + final formatter = NumberFormat('#,###', 'id_ID'); + final formattedPrice = formatter.format(price); + + return await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) { + return AlertDialog( + title: const Text('Konfirmasi Harga'), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text('Anda akan menetapkan harga Rp $formattedPrice'), + const SizedBox(height: 16), + const Text('Apakah harga ini sudah benar?'), + ], + ), + ), + actions: [ + TextButton( + child: const Text('Batal'), + onPressed: () { + Navigator.of(dialogContext).pop(false); + }, + ), + TextButton( + child: const Text('Benar'), + onPressed: () { + Navigator.of(dialogContext).pop(true); + }, + ), + ], + ); + }, + ) ?? false; + } + + // Method untuk memilih tanggal penyelesaian + Future _selectCompletionDate(BuildContext context) async { + final DateTime now = DateTime.now(); + final DateTime? picked = await showDatePicker( + context: context, + initialDate: DateTime.tryParse(_completionDateController.text) ?? now.add(const Duration(days: 7)), + firstDate: now, + lastDate: now.add(const Duration(days: 365)), + builder: (context, child) { + return Theme( + data: ThemeData.light().copyWith( + colorScheme: const ColorScheme.light( + primary: Color(0xFF1A2552), + onPrimary: Colors.white, + surface: Colors.white, + onSurface: Colors.black, + ), dialogTheme: const DialogThemeData(backgroundColor: Colors.white), + ), + child: child!, + ); + }, + ); + + if (picked != null) { + setState(() { + _completionDateController.text = DateFormat('yyyy-MM-dd').format(picked); + }); + } + } + + // Dialog konfirmasi harga dan tanggal penyelesaian + Future _showPriceAndDateConfirmationDialog(String price, String completionDate) async { + // Format harga dengan pemisah ribuan + final cleanedPrice = price.replaceAll(RegExp(r'[^0-9]'), ''); + final formattedPrice = _formatRupiah(cleanedPrice); + + // Format tanggal + DateTime parsedDate; + try { + parsedDate = DateTime.parse(completionDate); + } catch (e) { + parsedDate = DateTime.now(); + } + final formattedDate = DateFormat('d MMMM yyyy').format(parsedDate); + + return await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) { + return AlertDialog( + title: const Text('Konfirmasi', style: TextStyle(fontWeight: FontWeight.bold)), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Simpan perubahan berikut?'), + const SizedBox(height: 16), + + Row( + children: [ + const Text('Harga: ', style: TextStyle(fontWeight: FontWeight.bold)), + Text('Rp $formattedPrice'), + ], + ), + + const SizedBox(height: 8), + + Row( + children: [ + const Text('Tanggal Selesai: ', style: TextStyle(fontWeight: FontWeight.bold)), + Text(formattedDate), + ], + ), + ], + ), + actions: [ + TextButton( + child: const Text('Batal'), + onPressed: () { + Navigator.of(dialogContext).pop(false); + }, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + ), + child: const Text('Simpan', style: TextStyle(color: Colors.white)), + onPressed: () { + Navigator.of(dialogContext).pop(true); + }, + ), + ], + ); + }, + ) ?? false; + } +} diff --git a/TA_android/lib/pages/tailor/order/order_page.dart b/TA_android/lib/pages/tailor/order/order_page.dart new file mode 100644 index 0000000..f9e7fa5 --- /dev/null +++ b/TA_android/lib/pages/tailor/order/order_page.dart @@ -0,0 +1,1371 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../../core/providers/user_provider.dart'; +import '../../../core/models/user_model.dart'; +import '../../../core/services/api_service.dart'; +import '../../../core/models/booking_model.dart'; +import 'order_detail_Page.dart'; // Import halaman detail pesanan +import '../schedule/schedule_page.dart'; // Import halaman schedule +// ignore_for_file: avoid_print + +class OrderPage extends StatefulWidget { + const OrderPage({super.key}); + + @override + State createState() => _OrderPageState(); +} + +class _OrderPageState extends State { + bool _isLoading = true; + List _bookings = []; + String _errorMessage = ''; + String _currentStatus = 'semua'; // Status default: semua pesanan + + @override + void initState() { + super.initState(); + _fetchBookings(); + } + + // Fungsi untuk mendapatkan semua pesanan + Future _fetchBookings() async { + setState(() { + _isLoading = true; + _errorMessage = ''; + _currentStatus = 'semua'; + }); + + try { + final result = await ApiService.getTailorBookings(); + + if (mounted) { + setState(() { + _isLoading = false; + if (result['success']) { + final List bookingsJson = result['bookings']; + _bookings = bookingsJson + .map((json) => BookingModel.fromJson(json)) + .toList(); + } else { + _errorMessage = result['message']; + } + }); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + }); + } + } + } + + // Fungsi baru untuk mendapatkan pesanan berdasarkan status + Future _fetchBookingsByStatus(String status) async { + // Jika status = semua, gunakan API yang lama + if (status == 'semua') { + return _fetchBookings(); + } + + setState(() { + _isLoading = true; + _errorMessage = ''; + _currentStatus = status; + }); + + try { + // Untuk status 'menunggu', kita ambil dari API getTailorBookings dan filter + if (status == 'menunggu') { + final result = await ApiService.getTailorBookings(); + + if (mounted) { + setState(() { + _isLoading = false; + if (result['success']) { + final List bookingsJson = + result['bookings'] ?? result['data'] ?? []; + print( + 'DEBUG: Got ${bookingsJson.length} bookings, filtering for reservasi'); + + // Filter hanya pesanan dengan status 'reservasi' + final List filteredBookings = bookingsJson.where((booking) { + final String bookingStatus = + (booking['status'] ?? '').toString().toLowerCase(); + print('DEBUG: Booking status: $bookingStatus'); + return bookingStatus == 'reservasi'; + }).toList(); + + print( + 'DEBUG: Found ${filteredBookings.length} bookings with reservasi status'); + + _bookings = filteredBookings + .map((json) => BookingModel.fromJson(json)) + .toList(); + } else { + _errorMessage = result['message']; + } + }); + } + } else { + // Untuk status lain (diterima, diproses, selesai, dibatalkan) + final result = await ApiService.getTailorBookingsByStatus(status); + + if (mounted) { + setState(() { + _isLoading = false; + if (result['success']) { + final List bookingsJson = + result['bookings'] ?? result['data'] ?? []; + _bookings = bookingsJson + .map((json) => BookingModel.fromJson(json)) + .toList(); + } else { + _errorMessage = result['message']; + } + }); + } + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + }); + } + print('ERROR: Failed to fetch bookings by status: $e'); + } + } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (context, userProvider, child) { + final User? user = userProvider.user; + + // Jika tidak ada data user, tampilkan loading + if (user == null) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + return Scaffold( + backgroundColor: Colors.grey.shade50, + appBar: AppBar( + title: Row( + children: [ + // Foto profil + Container( + width: 35, + height: 35, + margin: const EdgeInsets.only(right: 10), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey.shade300, + border: Border.all( + color: Colors.grey.shade200, + width: 1, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(35), + child: user.profilePhoto != null && + user.profilePhoto!.isNotEmpty + ? Image.network( + _getFullProfilePhotoUrl(user.profilePhoto!), + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon( + Icons.person, + color: Colors.white, + size: 20, + ), + ); + }, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return const Center( + child: SizedBox( + width: 15, + height: 15, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ), + ); + }, + ) + : Image.asset( + 'assets/images/tailor_default.png', + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon( + Icons.person, + color: Colors.white, + size: 20, + ), + ); + }, + ), + ), + ), + Text( + user.name, + style: const TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + actions: [ + IconButton( + icon: const Icon(Icons.refresh, color: Color(0xFF1A2552)), + onPressed: () { + // Refresh data sesuai dengan status yang sedang aktif + if (_currentStatus == 'semua') { + _fetchBookings(); + } else { + _fetchBookingsByStatus(_currentStatus); + } + }, + ), + IconButton( + icon: const Icon(Icons.calendar_month_outlined, + color: Color(0xFF1A2552)), + onPressed: () { + // Navigasi ke halaman kalender jadwal + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SchedulePage(), + ), + ); + }, + ), + ], + ), + body: Column( + children: [ + // Tab filter untuk status pesanan + Container( + color: Colors.white, + child: Column( + children: [ + SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 8, + ), + child: Row( + children: [ + _buildStatusTab('semua', 'Semua'), + _buildStatusTab('menunggu', 'Menunggu'), + _buildStatusTab('diproses', 'Sedang Diproses'), + _buildStatusTab('selesai', 'Selesai'), + _buildStatusTab('dibatalkan', 'Dibatalkan'), + ], + ), + ), + const Divider( + height: 1, thickness: 1, color: Color(0xFFEEEEEE)), + ], + ), + ), + + // Tombol refresh + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + child: Row( + children: [ + Text('Daftar Pesanan', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: Colors.grey.shade800)), + const Spacer(), + InkWell( + onTap: () { + // Refresh data sesuai dengan status yang sedang aktif + if (_currentStatus == 'semua') { + _fetchBookings(); + } else { + _fetchBookingsByStatus(_currentStatus); + } + }, + borderRadius: BorderRadius.circular(20), + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF1A2552).withOpacity(0.1), + borderRadius: BorderRadius.circular(20), + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.refresh, + color: Color(0xFF1A2552), size: 16), + SizedBox(width: 4), + Text( + 'Refresh', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w500, + fontSize: 12, + ), + ), + ], + ), + ), + ) + ], + ), + ), + + // Konten utama + Expanded( + child: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _errorMessage.isNotEmpty + ? _buildErrorState(_errorMessage) + : _bookings.isEmpty + ? _buildEmptyState() + : _buildOrderList(), + ), + ], + ), + ); + }); + } + + Widget _buildStatusTab(String status, String label) { + final bool isActive = _currentStatus == status; + + return GestureDetector( + onTap: () { + if (status == 'semua') { + _fetchBookings(); + } else { + _fetchBookingsByStatus(status); + } + }, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 4), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: isActive ? const Color(0xFF1A2552) : Colors.white, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: isActive ? const Color(0xFF1A2552) : Colors.grey.shade300, + width: 1, + ), + boxShadow: isActive + ? [ + BoxShadow( + color: const Color(0xFF1A2552).withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + spreadRadius: 0, + ) + ] + : null, + ), + child: Text( + label, + style: TextStyle( + color: isActive ? Colors.white : Colors.grey.shade700, + fontWeight: isActive ? FontWeight.bold : FontWeight.normal, + ), + ), + ), + ); + } + + Widget _buildEmptyState() { + String statusText = ''; + + switch (_currentStatus) { + case 'semua': + statusText = 'Belum ada pesanan'; + break; + case 'menunggu': + statusText = 'Belum ada pesanan yang menunggu konfirmasi'; + break; + case 'diproses': + statusText = 'Belum ada pesanan yang sedang diproses'; + break; + case 'selesai': + statusText = 'Belum ada pesanan yang selesai'; + break; + case 'dibatalkan': + statusText = 'Belum ada pesanan yang dibatalkan'; + break; + } + + return Center( + child: Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.05), + blurRadius: 10, + spreadRadius: 0, + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: Colors.grey.shade100, + shape: BoxShape.circle, + ), + child: Icon( + _currentStatus == 'dibatalkan' + ? Icons.cancel_outlined + : _currentStatus == 'menunggu' + ? Icons.hourglass_empty + : Icons.inbox_outlined, + size: 40, + color: _currentStatus == 'dibatalkan' + ? Colors.red.shade300 + : _currentStatus == 'menunggu' + ? Colors.orange.shade400 + : Colors.grey.shade400, + ), + ), + const SizedBox(height: 16), + Text( + statusText, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 8), + Text( + 'Pesanan akan muncul di sini ketika tersedia', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } + + Widget _buildErrorState(String message) { + // Pesan yang lebih user-friendly untuk berbagai error + String displayMessage = message; + String detailMessage = ''; + + // Jika pesan error terkait status tidak valid + if (message.contains('Status tidak valid')) { + displayMessage = 'Terjadi Kesalahan'; + if (_currentStatus == 'menunggu') { + detailMessage = + 'Tidak dapat memuat pesanan yang menunggu konfirmasi. Silakan gunakan tab "Semua" untuk melihat semua pesanan.'; + } else { + detailMessage = 'Status tidak valid. Coba pilih tab status lainnya.'; + } + } else if (message.contains('Token tidak ditemukan')) { + displayMessage = 'Sesi Habis'; + detailMessage = 'Silakan login kembali untuk melanjutkan.'; + } else if (message.contains('No connection')) { + displayMessage = 'Tidak Ada Koneksi Internet'; + detailMessage = 'Periksa koneksi internet Anda dan coba lagi.'; + } + + return Center( + child: Container( + padding: const EdgeInsets.all(24), + margin: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.05), + blurRadius: 10, + spreadRadius: 0, + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: Colors.red.shade50, + shape: BoxShape.circle, + ), + child: Icon( + Icons.error_outline, + size: 40, + color: Colors.red.shade300, + ), + ), + const SizedBox(height: 16), + Text( + displayMessage, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 8), + Text( + detailMessage.isNotEmpty ? detailMessage : message, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () { + if (_currentStatus == 'semua') { + _fetchBookings(); + } else { + _fetchBookingsByStatus(_currentStatus); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 12, + ), + ), + child: const Text('Coba Lagi'), + ), + ], + ), + ), + ); + } + + Widget _buildOrderList() { + return ListView.builder( + padding: const EdgeInsets.all(16), + itemCount: _bookings.length, + itemBuilder: (context, index) { + final booking = _bookings[index]; + return _buildOrderCard(booking); + }, + ); + } + + Widget _buildOrderCard(BookingModel booking) { + // Mendapatkan warna berdasarkan status + Color statusColor; + switch (booking.status.toLowerCase()) { + case 'diterima': + statusColor = Colors.green; + break; + case 'diproses': + statusColor = Colors.blue; + break; + case 'selesai': + statusColor = Colors.purple; + break; + case 'dibatalkan': + statusColor = Colors.red; + break; + default: + statusColor = Colors.orange; + } + + // Debug untuk foto profil + final String? photoPath = booking.getCustomerPhoto(); + final String photoUrl = + photoPath != null ? _getFullProfilePhotoUrl(photoPath) : ''; + print('DEBUG: Customer photo path: $photoPath'); + print('DEBUG: Full photo URL: $photoUrl'); + + // Cek apakah status adalah reservasi + final bool isReservasi = booking.status.toLowerCase() == 'reservasi'; + + // Cek status pembayaran + final String paymentStatus = (booking.paymentStatus ?? '').toLowerCase(); + final bool isPaid = paymentStatus == 'paid'; + + // Cek apakah pesanan dibatalkan + final bool isCancelled = booking.status.toLowerCase() == 'dibatalkan'; + final String? rejectionReason = booking.rejectionReason; + + return Card( + margin: const EdgeInsets.only(bottom: 16), + elevation: 0, + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + offset: const Offset(0, 2), + blurRadius: 6, + spreadRadius: 0, + ), + BoxShadow( + color: statusColor.withOpacity(0.05), + offset: const Offset(0, 1), + blurRadius: 5, + spreadRadius: 0, + ), + ], + ), + child: InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => OrderDetailPage( + booking: booking, + ), + ), + ).then((_) { + // Refresh data setelah kembali dari halaman detail + if (_currentStatus == 'semua') { + _fetchBookings(); + } else { + _fetchBookingsByStatus(_currentStatus); + } + }); + }, + borderRadius: BorderRadius.circular(12), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header dengan status pesanan dan badge pembayaran yang lebih baik + Row( + children: [ + // Foto profil pelanggan + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.grey.shade200, + border: Border.all( + color: Colors.grey.shade100, + width: 1, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(40), + child: booking.getCustomerPhoto() != null && + booking.getCustomerPhoto()!.isNotEmpty + ? Image.network( + _getFullProfilePhotoUrl( + booking.getCustomerPhoto()!), + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + print( + 'ERROR: Failed to load profile image: $error'); + return const Icon(Icons.person); + }, + ) + : const Icon(Icons.person), + ), + ), + const SizedBox(width: 12), + + // Informasi pelanggan + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + booking.getCustomerName(), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + Text( + 'Pesanan #${booking.id}', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 12, + ), + ), + ], + ), + ), + + // Status badges - display both order status and payment status + if (booking.status.toLowerCase() == 'selesai') + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + // Status pesanan + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: Colors.purple.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.purple), + ), + child: const Text( + 'Selesai', + style: TextStyle( + color: Colors.purple, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 4), + // Status pembayaran + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + decoration: BoxDecoration( + color: isPaid + ? const Color(0xFF34A853).withOpacity(0.1) + : Colors.grey.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: isPaid + ? const Color(0xFF34A853) + : Colors.grey, + width: 1, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + isPaid ? Icons.check_circle : Icons.pending, + size: 12, + color: isPaid + ? const Color(0xFF34A853) + : Colors.grey, + ), + const SizedBox(width: 4), + Text( + isPaid ? 'Lunas' : 'Belum Bayar', + style: TextStyle( + color: isPaid + ? const Color(0xFF34A853) + : Colors.grey, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ) + else + // Status pesanan saja jika bukan status 'selesai' + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: statusColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: statusColor), + ), + child: Text( + _getStatusText(booking.status), + style: TextStyle( + color: statusColor, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + + const SizedBox(height: 16), + + // Tampilkan kode transaksi jika tersedia + if (booking.transactionCode != null && booking.transactionCode!.isNotEmpty) ...[ + Container( + margin: const EdgeInsets.only(bottom: 16), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade200), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.receipt_long, size: 14, color: Colors.blue.shade700), + const SizedBox(width: 6), + Text( + booking.transactionCode!, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.blue.shade700, + ), + ), + ], + ), + ), + ], + + Divider(color: Colors.grey.shade100, thickness: 1), + const SizedBox(height: 16), + + // Tampilan khusus untuk status reservasi + if (isReservasi) ...[ + // Menampilkan tanggal janji + _buildOrderDetail( + 'Tanggal Janji', booking.getFormattedDate()), + const SizedBox(height: 8), + // Menampilkan waktu + _buildOrderDetail('Waktu', booking.appointmentTime), + const SizedBox(height: 8), + // Menampilkan jenis layanan + _buildOrderDetail('Jenis Layanan', booking.serviceType), + const SizedBox(height: 8), + // Menampilkan kategori + _buildOrderDetail('Kategori', booking.category), + ] else ...[ + // Detail pesanan untuk status selain reservasi (tampilan default) + _buildOrderDetail( + 'Tanggal Janji', booking.getFormattedDate()), + const SizedBox(height: 8), + _buildOrderDetail('Waktu', booking.appointmentTime), + const SizedBox(height: 8), + _buildOrderDetail('Jenis Layanan', booking.serviceType), + const SizedBox(height: 8), + _buildOrderDetail('Kategori', booking.category), + ], + + // Menampilkan metode pembayaran + if (booking.paymentMethod != null && booking.paymentMethod!.isNotEmpty) ...[ + const SizedBox(height: 8), + _buildOrderDetail('Metode Pembayaran', _getPaymentMethodText(booking.paymentMethod!)), + ], + + // Jika status dibatalkan, tampilkan alasan penolakan + if (isCancelled && + rejectionReason != null && + rejectionReason.isNotEmpty) ...[ + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.red.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.red.shade200), + ), + child: Row( + children: [ + Icon(Icons.cancel, + color: Colors.red.shade700, size: 16), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Alasan Penolakan', + style: TextStyle( + color: Colors.red.shade700, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + rejectionReason, + style: TextStyle( + color: Colors.red.shade900, + fontSize: 14, + ), + ), + ], + ), + ), + ], + ), + ), + ], + + // Jika status selesai dan ada tanggal pengambilan, tampilkan informasi dengan desain yang lebih modern + if (booking.status.toLowerCase() == 'selesai' && + booking.pickupDate != null && + booking.pickupDate!.isNotEmpty) ...[ + const SizedBox(height: 12), + Container( + padding: + const EdgeInsets.symmetric(vertical: 8, horizontal: 10), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade100), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.event_note, + color: Colors.blue.shade700, size: 16), + const SizedBox(width: 6), + Text( + 'Pengambilan: ${_formatDate(booking.pickupDate!)}', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.blue.shade800, + ), + ), + ], + ), + ), + ], + + const SizedBox(height: 16), + + // Tombol aksi berdasarkan status + if (isReservasi) + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + OutlinedButton( + onPressed: () { + // Tampilkan dialog atau navigasi ke halaman penolakan + _showRejectDialog(booking.id); + }, + style: OutlinedButton.styleFrom( + foregroundColor: Colors.red, + side: const BorderSide(color: Colors.red), + ), + child: const Text('Tolak'), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: () async { + // Fungsi untuk menerima pesanan + try { + setState(() => _isLoading = true); + final result = + await ApiService.acceptBooking(booking.id); + setState(() => _isLoading = false); + + if (result['success']) { + // Tampilkan pesan sukses + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? + 'Pesanan berhasil diterima'), + backgroundColor: Colors.green, + ), + ); + } + + // Refresh data + if (_currentStatus == 'semua') { + _fetchBookings(); + } else { + _fetchBookingsByStatus(_currentStatus); + } + } else { + // Tampilkan pesan error + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? + 'Gagal menerima pesanan'), + backgroundColor: Colors.red, + ), + ); + } + } + } catch (e) { + setState(() => _isLoading = false); + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green, + foregroundColor: Colors.white, + ), + child: const Text('Terima'), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildOrderDetail(String label, String value) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + label, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + ), + Expanded( + child: Text( + value, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ); + } + + // Helper method untuk mendapatkan status text yang lebih user-friendly + String _getStatusText(String status) { + switch (status.toLowerCase()) { + case 'reservasi': + return 'Menunggu'; + case 'diterima': + return 'Diterima'; + case 'diproses': + return 'Diproses'; + case 'selesai': + return 'Selesai'; + case 'dibatalkan': + return 'Dibatalkan'; + default: + return status; + } + } + + // Helper method untuk memastikan URL lengkap + String _getFullProfilePhotoUrl(String photoUrl) { + try { + // Mencatat URL asli untuk debugging + print('DEBUG: PhotoURL original: $photoUrl'); + + // Jika URL sudah lengkap, kembalikan apa adanya + if (photoUrl.startsWith('http')) { + return photoUrl; + } + + // Bersihkan URL dari karakter tidak perlu + String cleanedUrl = photoUrl.trim(); + + // Jika URL dimulai dengan "/storage" + if (cleanedUrl.startsWith('/storage')) { + String result = '${ApiService.imageBaseUrl}$cleanedUrl'; + print('DEBUG: Fixed URL (case 1): $result'); + return result; + } + + // Jika dimulai dengan "storage/" + else if (cleanedUrl.startsWith('storage/')) { + String result = '${ApiService.imageBaseUrl}/$cleanedUrl'; + print('DEBUG: Fixed URL (case 2): $result'); + return result; + } + + // Jika dimulai dengan "/" + else if (cleanedUrl.startsWith('/')) { + String result = '${ApiService.imageBaseUrl}$cleanedUrl'; + print('DEBUG: Fixed URL (case 3): $result'); + return result; + } + + // Jika tidak memiliki awalan slash + else { + String result = '${ApiService.imageBaseUrl}/$cleanedUrl'; + print('DEBUG: Fixed URL (case 4): $result'); + return result; + } + } catch (e) { + print('ERROR: Gagal memproses URL foto: $e untuk photoUrl=$photoUrl'); + return '${ApiService.imageBaseUrl}/placeholder.jpg'; // Return placeholder URL + } + } + + // Fungsi untuk menampilkan dialog penolakan pesanan + Future _showRejectDialog(int bookingId) async { + final TextEditingController reasonController = TextEditingController(); + bool isSubmitting = false; + + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) { + return StatefulBuilder(builder: (context, setState) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + backgroundColor: Colors.white, + elevation: 8, + title: Column( + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: Colors.red.shade50, + shape: BoxShape.circle, + ), + child: Icon( + Icons.close, + color: Colors.red.shade400, + size: 24, + ), + ), + const SizedBox(height: 16), + const Text( + 'Tolak Pesanan', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Berikan alasan mengapa Anda menolak pesanan ini', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + const SizedBox(height: 16), + TextField( + controller: reasonController, + decoration: InputDecoration( + hintText: 'Alasan penolakan...', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.red.shade200), + ), + filled: true, + fillColor: Colors.grey.shade50, + contentPadding: const EdgeInsets.all(12), + ), + maxLines: 3, + ), + if (isSubmitting) + Container( + margin: const EdgeInsets.only(top: 16), + child: const Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.red), + ), + ), + ), + ], + ), + actions: [ + Row( + children: [ + Expanded( + child: TextButton( + onPressed: isSubmitting + ? null + : () => Navigator.of(dialogContext).pop(), + style: TextButton.styleFrom( + foregroundColor: Colors.grey.shade700, + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text('Batal'), + ), + ), + const SizedBox(width: 8), + Expanded( + child: ElevatedButton( + onPressed: isSubmitting + ? null + : () async { + if (reasonController.text.trim().isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: + Text('Mohon masukkan alasan penolakan'), + backgroundColor: Colors.red, + ), + ); + return; + } + + setState(() { + isSubmitting = true; + }); + + try { + final result = await ApiService.rejectBooking( + bookingId, reasonController.text.trim()); + + if (dialogContext.mounted) { + Navigator.of(dialogContext).pop(); + } + + if (context.mounted) { + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? + 'Pesanan berhasil ditolak'), + backgroundColor: Colors.green, + ), + ); + + // Refresh data + if (_currentStatus == 'semua') { + _fetchBookings(); + } else { + _fetchBookingsByStatus(_currentStatus); + } + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? + 'Gagal menolak pesanan'), + backgroundColor: Colors.red, + ), + ); + } + } + } catch (e) { + if (dialogContext.mounted) { + Navigator.of(dialogContext).pop(); + } + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + foregroundColor: Colors.white, + elevation: 0, + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text('Tolak Pesanan'), + ), + ), + ], + ), + ], + ); + }); + }, + ); + } + + // Helper untuk memformat tanggal + String _formatDate(String isoDate) { + try { + final DateTime date = DateTime.parse(isoDate); + return "${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year}"; + } catch (e) { + return isoDate; + } + } + + // Helper function untuk mendapatkan teks metode pembayaran + String _getPaymentMethodText(String method) { + switch (method.toLowerCase()) { + case 'transfer_bank': + return 'Transfer Bank'; + case 'cod': + case 'cash_on_delivery': + return 'Cash on Delivery (COD)'; + default: + return method; + } + } +} diff --git a/TA_android/lib/pages/tailor/order/temp_edit.dart b/TA_android/lib/pages/tailor/order/temp_edit.dart new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/TA_android/lib/pages/tailor/order/temp_edit.dart @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/TA_android/lib/pages/tailor/order/temp_reject_booking.dart b/TA_android/lib/pages/tailor/order/temp_reject_booking.dart new file mode 100644 index 0000000..fc2921b --- /dev/null +++ b/TA_android/lib/pages/tailor/order/temp_reject_booking.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import '../../../core/services/api_service.dart'; +import '../../../core/models/booking_model.dart'; + +// Copy metode ini ke OrderDetailPage.dart untuk menggantikan metode _rejectBooking yang ada +Future improvedRejectBooking(BuildContext context, BookingModel? booking, + String reason, Function(bool) setState, bool mounted) async { + if (!mounted || booking == null) return; + + if (reason.trim().isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Alasan penolakan harus diisi'), + backgroundColor: Colors.red, + ), + ); + return; + } + + // Validasi status booking + final status = booking.status.toLowerCase(); + if (status != 'reservasi') { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Tidak Dapat Menolak Pesanan'), + content: Text( + 'Pesanan dengan status "${booking.getStatusText()}" tidak dapat ditolak. Hanya pesanan dengan status "Menunggu Konfirmasi" yang dapat ditolak.'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Mengerti'), + ), + ], + ); + }, + ); + return; + } + + setState(true); // Set _isProcessing = true + + try { + final result = await ApiService.rejectBooking(booking.id, reason); + + if (!mounted) return; + + setState(false); // Set _isProcessing = false + + if (result['success']) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message']), + backgroundColor: Colors.green, + ), + ); + // Kembali ke halaman sebelumnya + Navigator.pop(context, true); + } else { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Gagal Menolak Pesanan'), + content: Text(result['message']), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Tutup'), + ), + ], + ); + }, + ); + } + } catch (e) { + if (!mounted) return; + + setState(false); // Set _isProcessing = false + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Terjadi kesalahan: $e'), + backgroundColor: Colors.red, + ), + ); + } +} + +// Implementasi di OrderDetailPage.dart: +/* +Future _rejectBooking(String reason) async { + setState(() { + _isProcessing = true; + }); + + await improvedRejectBooking( + context, + _booking, + reason, + (bool isProcessing) => setState(() { _isProcessing = isProcessing; }), + mounted + ); +} +*/ \ No newline at end of file diff --git a/TA_android/lib/pages/tailor/profile/profile_page.dart b/TA_android/lib/pages/tailor/profile/profile_page.dart new file mode 100644 index 0000000..a9d274d --- /dev/null +++ b/TA_android/lib/pages/tailor/profile/profile_page.dart @@ -0,0 +1,1334 @@ +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:provider/provider.dart'; +import 'dart:io'; +import '../../../core/widgets/custom_button.dart'; +import '../../../core/controllers/auth_controller.dart'; +import '../../../core/controllers/profile_controller.dart'; +import '../../../core/routes/routes.dart'; +import '../../../core/providers/user_provider.dart'; +import '../../../core/models/user_model.dart'; +import '../../../core/widgets/gallery_grid_widget.dart'; +import '../../../core/services/api_service.dart'; +import '../../../core/utils/logger.dart'; +import '../../../core/controllers/gallery_controller.dart'; +import '../../../core/models/gallery_item_model.dart'; +// ignore_for_file: avoid_print + +class ProfilePage extends StatefulWidget { + const ProfilePage({super.key}); + + @override + State createState() => _ProfilePageState(); +} + +class _ProfilePageState extends State { + final AuthController _authController = AuthController(); + final ProfileController _profileController = ProfileController(); + final ApiService _apiService = ApiService(); + final ImagePicker _imagePicker = ImagePicker(); + final GalleryController _galleryController = GalleryController(); + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _phoneController = TextEditingController(); + final TextEditingController _addressController = TextEditingController(); + final TextEditingController _shopDescriptionController = + TextEditingController(); + File? _profileImage; + bool _isLoading = false; + bool _isUploadingPhoto = false; + bool _isRefreshingGallery = false; + bool _isLoadingProfilePhoto = false; + // Tambahkan Map untuk menyimpan mapping URL ke ID galeri + final Map _galleryUrlToId = {}; + + @override + void initState() { + super.initState(); + _loadUserData(); + _loadGalleryData(); + } + + void _loadUserData() { + final userProvider = Provider.of(context, listen: false); + if (userProvider.user != null) { + setState(() { + _nameController.text = userProvider.user!.name; + _emailController.text = userProvider.user!.email; + _phoneController.text = userProvider.user!.phoneNumber; + _addressController.text = userProvider.user!.address; + _shopDescriptionController.text = + userProvider.user!.shopDescription ?? ''; + }); + } + } + + Future _pickAndUploadProfileImage() async { + try { + final pickedFile = + await _imagePicker.pickImage(source: ImageSource.gallery); + + if (pickedFile != null) { + setState(() { + _isLoadingProfilePhoto = true; + _isUploadingPhoto = true; + }); + + AppLogger.info('Memulai upload foto profil: ${pickedFile.path}'); + _showLoadingDialog(context, 'Mengunggah foto profil...'); + + await _profileController.uploadProfilePhoto( + context, File(pickedFile.path)); + + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + + setState(() { + _isLoadingProfilePhoto = false; + _isUploadingPhoto = false; + }); + + AppLogger.info('Upload foto profil selesai'); + } + } catch (e) { + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + + setState(() { + _isLoadingProfilePhoto = false; + _isUploadingPhoto = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Gagal mengunggah foto: $e')), + ); + AppLogger.error('Error in _pickAndUploadProfileImage: $e'); + } + } + + void _showLoadingDialog(BuildContext context, String message) { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 16), + Text(message), + ], + ), + ); + }, + ); + } + + Future _updateProfile() async { + setState(() { + _isLoading = true; + }); + + try { + // Siapkan data untuk update + final Map updateData = { + 'name': _nameController.text, + 'phone_number': _phoneController.text, + 'address': _addressController.text, + 'shop_description': _shopDescriptionController.text, + }; + + // Gunakan ProfileController untuk update profil + final success = + await _profileController.updateProfile(context, updateData); + + if (!success) { + AppLogger.warning('Gagal memperbarui profil', tag: 'ProfilePage'); + } + } catch (e) { + AppLogger.error('Error saat update profil', error: e, tag: 'ProfilePage'); + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal memperbarui profil: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + // Helper method untuk memastikan URL lengkap + String getFullProfilePhotoUrl(String photoUrl) { + print('DEBUG PROFILE: Processing photo URL: $photoUrl'); + + // Jika URL sudah lengkap, kembalikan apa adanya + if (photoUrl.startsWith('http')) { + print('DEBUG PROFILE: Photo URL is already complete'); + return photoUrl; + } + + // Jika tidak, tambahkan base URL + final fullUrl = + 'http://10.0.2.2:8000${photoUrl.startsWith('/') ? '' : '/'}$photoUrl'; + print('DEBUG PROFILE: Converted to full URL: $fullUrl'); + return fullUrl; + } + + return Consumer( + builder: (context, userProvider, child) { + final User? user = userProvider.user; + + // Jika tidak ada data user, tampilkan loading + if (user == null) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + // Log info user untuk debugging + print( + 'DEBUG PROFILE: User data loaded. Name: ${user.name}, Email: ${user.email}'); + print('DEBUG PROFILE: Profile photo URL: ${user.profilePhoto}'); + + // Log gallery data + if (user.gallery?.isNotEmpty ?? false) { + print('DEBUG PROFILE: Gallery count: ${user.gallery!.length}'); + } else { + print('DEBUG PROFILE: No gallery items available'); + } + + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: const Text( + 'Profil Penjahit', + style: TextStyle( + fontSize: 18, + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + centerTitle: true, + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + iconTheme: const IconThemeData(color: Color(0xFF1A2552)), + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios_new, size: 18), + onPressed: () { + // Kembali ke halaman utama + Navigator.pushReplacementNamed(context, AppRoutes.tailorHome); + }, + ), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Profile Image + Center( + child: Stack( + children: [ + Container( + width: 100, + height: 100, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: Colors.grey.shade300, + width: 1, + ), + ), + child: _isUploadingPhoto + ? ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Container( + color: Colors.grey.shade200, + child: const Center( + child: CircularProgressIndicator(), + ), + ), + ) + : ClipRRect( + borderRadius: BorderRadius.circular(50), + child: _profileImage != null + ? Image.file( + _profileImage!, + fit: BoxFit.cover, + ) + : user.profilePhoto != null + ? Image.network( + getFullProfilePhotoUrl( + user.profilePhoto!), + fit: BoxFit.cover, + loadingBuilder: (context, child, + loadingProgress) { + if (loadingProgress == null) { + print( + 'DEBUG PROFILE: Profile image loaded successfully'); + return child; + } + print( + 'DEBUG PROFILE: Loading profile image...'); + return Center( + child: + CircularProgressIndicator( + value: loadingProgress + .expectedTotalBytes != + null + ? loadingProgress + .cumulativeBytesLoaded / + loadingProgress + .expectedTotalBytes! + : null, + ), + ); + }, + errorBuilder: + (context, error, stackTrace) { + print( + 'DEBUG PROFILE: Error loading profile image: $error'); + return const Icon( + Icons.person, + size: 40, + color: Colors.grey, + ); + }, + ) + : Image.asset( + 'assets/images/tailor_default.png', + fit: BoxFit.cover, + errorBuilder: + (context, error, stackTrace) { + return Container( + color: Colors.grey.shade200, + child: const Icon( + Icons.person, + size: 40, + color: Colors.grey, + ), + ); + }, + ), + ), + ), + Positioned( + bottom: 0, + right: 0, + child: GestureDetector( + onTap: _isUploadingPhoto + ? null + : _pickAndUploadProfileImage, + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.3), + spreadRadius: 1, + blurRadius: 2, + offset: const Offset(0, 1), + ), + ], + ), + child: Icon( + Icons.camera_alt, + size: 20, + color: _isUploadingPhoto + ? Colors.grey.shade400 + : Colors.grey.shade700, + ), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + + // Badge Penjahit + // Container( + // padding: + // const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + // decoration: BoxDecoration( + // color: const Color(0xFF1A2552).withOpacity(0.1), + // borderRadius: BorderRadius.circular(12), + // ), + // child: Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Icon(Icons.verified_user, + // size: 16, color: const Color(0xFF1A2552)), + // const SizedBox(width: 4), + // Text( + // 'Penjahit Terverifikasi', + // style: TextStyle( + // fontSize: 12, + // color: const Color(0xFF1A2552), + // fontWeight: FontWeight.bold, + // ), + // ), + // ], + // ), + // ), + + // Email Verified Badge + if (user.emailVerifiedAt != null) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.green.shade100, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.verified, + size: 16, color: Colors.green.shade700), + const SizedBox(width: 4), + Text( + 'Email Terverifikasi', + style: TextStyle( + fontSize: 12, + color: Colors.green.shade700, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ), + + const SizedBox(height: 24), + + // Profile Form + _buildFormField( + label: 'Nama', + controller: _nameController, + ), + const SizedBox(height: 16), + + _buildFormField( + label: 'Email', + controller: _emailController, + readOnly: true, // Email tidak bisa diubah + ), + const SizedBox(height: 16), + + _buildFormField( + label: 'No. Handphone', + controller: _phoneController, + ), + const SizedBox(height: 16), + + _buildFormField( + label: 'Alamat', + controller: _addressController, + ), + const SizedBox(height: 16), + + // Shop Description + _buildFormField( + label: 'Deskripsi Toko', + controller: _shopDescriptionController, + maxLines: 4, + ), + const SizedBox(height: 24), + + // Tailor Gallery Section + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Galeri Toko', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + const Text( + 'Tambahkan foto-foto terbaik karya Anda untuk menarik pelanggan', + style: TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + const SizedBox(height: 16), + + // Menggunakan widget GalleryGridWidget + GalleryGridWidget( + galleryItems: user.gallery, + onTapItem: (imageUrl) => _showFullImage(imageUrl), + onLongPressItem: (imageUrl) => + _showDeleteGalleryDialog(imageUrl), + onAddItem: () => _showAddGalleryDialog(), + isLoading: _isLoading && + (user.gallery == null || user.gallery!.isEmpty), + isRefreshing: _isRefreshingGallery, + ), + + const SizedBox(height: 16), + ], + ), + + const SizedBox(height: 32), + + // Update Button + CustomButton( + text: 'Update Profil', + onPressed: _updateProfile, + isLoading: _isLoading, + borderRadius: 8, + backgroundColor: const Color(0xFF1E3A8A), + ), + + const SizedBox(height: 24), + + // Logout Button + CustomButton( + text: 'Logout', + onPressed: () { + // Tampilkan dialog konfirmasi logout + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Konfirmasi Logout'), + content: const Text( + 'Apakah Anda yakin ingin keluar dari aplikasi?'), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); // Tutup dialog + }, + child: const Text('Batal'), + ), + TextButton( + onPressed: () async { + // Tampilkan loading + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return const Center( + child: CircularProgressIndicator(), + ); + }, + ); + + // Proses logout + await _authController.logout(context); + + // Tutup loading dialog + Navigator.pop(context); + + // Tutup dialog konfirmasi + Navigator.pop(context); + + // Navigasi ke halaman login + Navigator.pushNamedAndRemoveUntil(context, + AppRoutes.loginTailor, (route) => false); + + // Tampilkan pesan sukses + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Berhasil logout'), + backgroundColor: Colors.green, + ), + ); + }, + child: const Text('Logout', + style: TextStyle(color: Colors.red)), + ), + ], + ), + ); + }, + borderRadius: 8, + backgroundColor: Colors.red, + ), + ], + ), + ), + ), + ); + }, + ); + } + + Widget _buildFormField({ + required String label, + required TextEditingController controller, + bool readOnly = false, + int maxLines = 1, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + TextField( + controller: controller, + readOnly: readOnly, + maxLines: maxLines, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: const BorderSide(color: Color(0xFF1A2552)), + ), + contentPadding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + filled: true, + fillColor: readOnly ? Colors.grey.shade100 : Colors.white, + ), + ), + ], + ); + } + + @override + void dispose() { + _nameController.dispose(); + _emailController.dispose(); + _phoneController.dispose(); + _addressController.dispose(); + _shopDescriptionController.dispose(); + _galleryController.dispose(); + super.dispose(); + } + + // Gallery methods + Future _showAddGalleryDialog() async { + AppLogger.info('Membuka dialog tambah foto galeri', tag: 'Dialog'); + + // Deklarasikan variabel di luar StatefulBuilder untuk dapat diakses dalam StatefulBuilder + File? selectedImage; + final titleController = TextEditingController(text: ''); + final descriptionController = TextEditingController(text: ''); + final categoryController = TextEditingController(text: 'umum'); + + // Fokus node dengan logging + final titleFocus = AppLogger.createLoggingFocusNode('Judul', tag: 'Dialog'); + final descriptionFocus = + AppLogger.createLoggingFocusNode('Deskripsi', tag: 'Dialog'); + final categoryFocus = + AppLogger.createLoggingFocusNode('Kategori', tag: 'Dialog'); + + void logFormStatus() { + AppLogger.form('Status validasi form', tag: 'Dialog', fields: { + 'gambar': selectedImage?.path, + 'judul': titleController.text, + 'deskripsi': descriptionController.text, + 'kategori': categoryController.text, + }); + } + + // Tampilkan dialog form menggunakan StatefulBuilder agar bisa update UI dialog + await showDialog( + context: context, + builder: (context) => StatefulBuilder( + builder: (context, setDialogState) { + // Cek apakah semua field terisi + bool isFormValid = selectedImage != null && + titleController.text.isNotEmpty && + descriptionController.text.isNotEmpty && + categoryController.text.isNotEmpty; + + // Log saat widget dibuild ulang + AppLogger.debug('Membangun dialog (form valid: $isFormValid)', + tag: 'Dialog'); + + return AlertDialog( + title: const Text('Tambah Foto Galeri'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Foto yang ditambahkan akan muncul di profil Anda dan dapat dilihat oleh pelanggan.', + style: TextStyle(fontSize: 12, color: Colors.grey), + ), + const SizedBox(height: 16), + + // Image preview + Center( + child: GestureDetector( + onTap: () async { + final ImagePicker picker = ImagePicker(); + final XFile? image = await picker.pickImage( + source: ImageSource.gallery, + imageQuality: 70, + ); + + if (image != null) { + AppLogger.debug('Gambar dipilih: ${image.path}', + tag: 'Dialog'); + // Perbarui UI dengan gambar baru tanpa menutup dialog + setDialogState(() { + selectedImage = File(image.path); + logFormStatus(); + }); + } + }, + child: Container( + width: 150, + height: 150, + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade300), + ), + child: selectedImage != null + ? ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + selectedImage!, + width: 150, + height: 150, + fit: BoxFit.cover, + ), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.add_photo_alternate_outlined, + size: 40, + color: Colors.grey.shade400, + ), + const SizedBox(height: 8), + Text( + 'Pilih Foto', + style: TextStyle( + color: Colors.grey.shade600, + fontSize: 14, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 16), + + // Title field + TextField( + controller: titleController, + focusNode: titleFocus, + decoration: const InputDecoration( + labelText: 'Judul *', + hintText: 'Contoh: Kemeja Formal Pria', + border: OutlineInputBorder(), + ), + onChanged: (value) { + AppLogger.debug('Judul berubah: "$value"', tag: 'Dialog'); + setDialogState(() { + logFormStatus(); + }); + }, + ), + const SizedBox(height: 16), + + // Description field + TextField( + controller: descriptionController, + focusNode: descriptionFocus, + maxLines: 3, + decoration: const InputDecoration( + labelText: 'Deskripsi *', + hintText: 'Berikan deskripsi mengenai foto ini', + border: OutlineInputBorder(), + ), + onChanged: (value) { + AppLogger.debug('Deskripsi berubah: "$value"', + tag: 'Dialog'); + setDialogState(() { + logFormStatus(); + }); + }, + ), + const SizedBox(height: 16), + + // Category field + TextField( + controller: categoryController, + focusNode: categoryFocus, + decoration: const InputDecoration( + labelText: 'Kategori *', + hintText: 'Contoh: Kemeja, Gaun, Celana', + border: OutlineInputBorder(), + ), + onChanged: (value) { + AppLogger.debug('Kategori berubah: "$value"', + tag: 'Dialog'); + setDialogState(() { + logFormStatus(); + }); + }, + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + AppLogger.debug('Dialog dibatalkan oleh pengguna', + tag: 'Dialog'); + Navigator.of(context).pop(); + }, + child: const Text('Batal'), + ), + ElevatedButton( + onPressed: isFormValid + ? () { + AppLogger.info('Menyimpan data galeri', tag: 'Dialog'); + AppLogger.form('Data yang akan disimpan', + tag: 'Dialog', + fields: { + 'gambar': selectedImage?.path, + 'judul': titleController.text, + 'deskripsi': descriptionController.text, + 'kategori': categoryController.text, + }); + + // Pastikan foto masih ada sebelum memanggil upload + if (selectedImage != null) { + Navigator.of(context).pop(); + _processGalleryUpload( + selectedImage!, + titleController.text, + descriptionController.text, + categoryController.text, + ); + } + } + : null, // Disable button if any required field is empty + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + ), + child: const Text('Simpan'), + ), + ], + ); + }, + ), + ); + + // Dispose controllers dan focus nodes + AppLogger.debug('Membuang controllers dan focus nodes', tag: 'Dialog'); + titleController.dispose(); + descriptionController.dispose(); + categoryController.dispose(); + titleFocus.dispose(); + descriptionFocus.dispose(); + categoryFocus.dispose(); + } + + Future _processGalleryUpload( + File imageFile, String title, String description, String category) async { + try { + setState(() { + _isUploadingPhoto = true; + }); + + _showLoadingDialog(context, 'Mengunggah foto galeri...'); + + final success = await _profileController.uploadGalleryPhoto( + context, + imageFile, + title: title, + description: description, + category: category, + ); + + // Tutup dialog loading + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + + if (success) { + _refreshGallery(); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Foto galeri berhasil ditambahkan')), + ); + } + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Gagal mengunggah foto: $e')), + ); + AppLogger.error('Error in _processGalleryUpload: $e'); + } finally { + setState(() { + _isUploadingPhoto = false; + }); + } + } + + void _showFullImage(String imageUrl) { + // Cari item galeri berdasarkan URL + final galleryItem = _galleryController.galleryItems.firstWhere( + (item) => item.fullPhotoUrl == imageUrl, + orElse: () => GalleryItem( + id: 0, + title: '', + description: '', + category: '', + photo: '', + fullPhotoUrl: '', + createdAt: '', + updatedAt: '', + ), + ); + + showDialog( + context: context, + builder: (context) => Dialog( + insetPadding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + AppBar( + backgroundColor: Colors.transparent, + elevation: 0, + title: Text(galleryItem.title.isNotEmpty ? galleryItem.title : 'Foto Galeri'), + actions: [ + IconButton( + icon: const Icon(Icons.delete, color: Colors.red), + onPressed: () { + Navigator.pop(context); + _showDeleteGalleryDialog(imageUrl); + }, + ), + ], + ), + Flexible( + child: InteractiveViewer( + panEnabled: true, + boundaryMargin: const EdgeInsets.all(20), + minScale: 0.5, + maxScale: 4, + child: Image.network( + imageUrl, + fit: BoxFit.contain, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + return Container( + color: Colors.grey.shade100, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.broken_image, + size: 64, + color: Colors.grey, + ), + const SizedBox(height: 8), + Text( + 'Gagal memuat gambar', + style: TextStyle(color: Colors.grey.shade700), + ), + ], + ), + ); + }, + ), + ), + ), + if (galleryItem.description.isNotEmpty) + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Deskripsi', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.grey.shade700, + ), + ), + const SizedBox(height: 8), + Text( + galleryItem.description, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ), + ], + ), + ), + if (galleryItem.category.isNotEmpty) + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), + child: Row( + children: [ + Icon( + Icons.category, + size: 16, + color: Colors.grey.shade600, + ), + const SizedBox(width: 8), + Text( + galleryItem.category, + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ), + ], + ), + ), + ], + ), + ), + ); + } + + void _showDeleteGalleryDialog(String imageUrl) { + // Cari item galeri berdasarkan URL + final galleryItem = _galleryController.galleryItems.firstWhere( + (item) => item.fullPhotoUrl == imageUrl, + orElse: () => GalleryItem( + id: 0, + title: '', + description: '', + category: '', + photo: '', + fullPhotoUrl: '', + createdAt: '', + updatedAt: '', + ), + ); + + print('DEBUG DELETE: =========================================='); + print('DEBUG DELETE: Memulai proses delete foto galeri'); + print('DEBUG DELETE: URL foto yang akan dihapus: $imageUrl'); + print('DEBUG DELETE: ID galeri: ${galleryItem.id}'); + print('DEBUG DELETE: =========================================='); + + if (galleryItem.id == 0) { + print('DEBUG DELETE: Item galeri tidak ditemukan'); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Item galeri tidak ditemukan'), + backgroundColor: Colors.red, + ), + ); + return; + } + + showDialog( + context: context, + builder: (dialogContext) => AlertDialog( + title: const Text('Hapus Foto'), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Apakah Anda yakin ingin menghapus foto ini dari galeri?', + style: TextStyle(fontSize: 16), + ), + const SizedBox(height: 12), + const Text( + 'Tindakan ini tidak dapat dibatalkan.', + style: TextStyle( + fontSize: 12, + color: Colors.red, + fontStyle: FontStyle.italic), + ), + const SizedBox(height: 16), + Container( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.3, + maxWidth: MediaQuery.of(context).size.width * 0.8, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.network( + imageUrl, + fit: BoxFit.contain, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return Container( + height: 150, + color: Colors.grey.shade200, + child: Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ), + ); + }, + errorBuilder: (context, error, stackTrace) { + return Container( + height: 150, + color: Colors.grey.shade200, + child: const Center( + child: Icon(Icons.error_outline, + color: Colors.grey, size: 40), + ), + ); + }, + ), + ), + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(dialogContext); + }, + child: const Text('Batal'), + ), + TextButton( + onPressed: () async { + Navigator.pop(dialogContext); + + if (!context.mounted) return; + + _showLoadingDialog(context, 'Menghapus foto dari galeri...'); + + try { + final success = await _galleryController.deleteGalleryItem( + context, + galleryItem.id, + ); + + // Tutup dialog loading + if (context.mounted && Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + + if (success) { + print('DEBUG DELETE: Foto berhasil dihapus'); + _refreshGallery(); + } + } catch (e, stackTrace) { + print('DEBUG DELETE: =========================================='); + print('DEBUG DELETE: Error saat menghapus foto:'); + print('DEBUG DELETE: Error: $e'); + print('DEBUG DELETE: Stack trace: $stackTrace'); + print('DEBUG DELETE: =========================================='); + + // Pastikan dialog loading ditutup jika terjadi error + if (context.mounted && Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Gagal menghapus foto: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + }, + child: const Text('Hapus', style: TextStyle(color: Colors.red)), + ), + ], + ), + ); + } + + // Metode untuk memuat data galeri + Future _loadGalleryData() async { + if (mounted) { + setState(() { + _isLoading = true; + }); + } + + try { + print('DEBUG GALLERY: Memulai proses load data galeri'); + AppLogger.info('Memuat data galeri...', tag: 'Gallery'); + + // Gunakan GalleryController untuk fetch data + final success = await _galleryController.fetchGalleryItems(context); + + if (success) { + print('DEBUG GALLERY: Data galeri berhasil dimuat'); + print('DEBUG GALLERY: Jumlah item: ${_galleryController.galleryItems.length}'); + + // Update galeri di UserProvider + final userProvider = Provider.of(context, listen: false); + if (userProvider.user != null) { + final galleryUrls = _galleryController.galleryItems + .map((item) => item.fullPhotoUrl) + .toList(); + userProvider.updateUserGallery(galleryUrls); + print('DEBUG GALLERY: Galeri berhasil diperbarui di UserProvider'); + } + } else { + print('DEBUG GALLERY: Gagal memuat data galeri'); + } + } catch (e, stackTrace) { + print('DEBUG GALLERY: Error saat load data galeri:'); + print('DEBUG GALLERY: Error: $e'); + print('DEBUG GALLERY: Stack trace: $stackTrace'); + AppLogger.error('Exception loading gallery', error: e, tag: 'Gallery'); + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + print('DEBUG GALLERY: Proses load data galeri selesai'); + } + } + } + + // Metode untuk merefresh galeri + Future _refreshGallery() async { + if (!mounted) { + AppLogger.warning( + 'Tidak dapat me-refresh galeri: widget tidak lagi mounted', + tag: 'Gallery'); + return; + } + + // Simpan referensi ke UserProvider di awal metode + UserProvider? userProvider; + try { + userProvider = Provider.of(context, listen: false); + } catch (e) { + AppLogger.error('Tidak dapat mengakses UserProvider untuk refresh galeri', + error: e, tag: 'Gallery'); + return; + } + + setState(() { + _isRefreshingGallery = true; + }); + + try { + AppLogger.info('Merefresh data galeri...', tag: 'Gallery'); + final result = await ApiService.getTailorGallery(); + AppLogger.api('Respons API refresh galeri:', + data: result, tag: 'Gallery'); + + if (result['success'] && result['data'] != null) { + final List galleryData = result['data']; + final List galleryUrls = []; + + // Ekstrak URL foto dari data galeri + AppLogger.debug('Mengekstrak URL foto dari ${galleryData.length} item', + tag: 'Gallery'); + for (var item in galleryData) { + if (item is Map) { + String? photoUrl; + + // Prioritaskan full_photo_url jika tersedia + if (item.containsKey('full_photo_url') && + item['full_photo_url'] != null) { + photoUrl = item['full_photo_url']; + AppLogger.debug('Menggunakan full_photo_url: $photoUrl', + tag: 'Gallery'); + } + // Gunakan photo jika full_photo_url tidak tersedia + else if (item.containsKey('photo') && item['photo'] != null) { + // Gunakan utility method untuk mendapatkan URL lengkap + String photo = item['photo']; + photoUrl = ApiService.getFullImageUrl(photo); + AppLogger.debug('Menggunakan photo dengan URL lengkap: $photoUrl', + tag: 'Gallery'); + } + + // Tambahkan URL ke list jika valid + if (photoUrl != null && photoUrl.isNotEmpty) { + galleryUrls.add(photoUrl); + } + } + } + + AppLogger.info( + 'Jumlah foto galeri yang direfresh: ${galleryUrls.length}', + tag: 'Gallery'); + + // Update galeri di UserProvider jika masih valid + if (userProvider.user != null) { + await userProvider.updateUserGallery(galleryUrls); + AppLogger.debug('Galeri berhasil direfresh di UserProvider', + tag: 'Gallery'); + } else { + AppLogger.warning( + 'User tidak tersedia, tidak dapat memperbarui galeri', + tag: 'Gallery'); + } + } else { + AppLogger.warning('Error refreshing gallery: ${result['message']}', + tag: 'Gallery'); + } + } catch (e) { + AppLogger.error('Exception refreshing gallery', error: e, tag: 'Gallery'); + } finally { + if (mounted) { + setState(() { + _isRefreshingGallery = false; + }); + } + } + } +} diff --git a/TA_android/lib/pages/tailor/schedule/schedule_page.dart b/TA_android/lib/pages/tailor/schedule/schedule_page.dart new file mode 100644 index 0000000..688e8bd --- /dev/null +++ b/TA_android/lib/pages/tailor/schedule/schedule_page.dart @@ -0,0 +1,503 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'package:tailorhub/core/services/api_service.dart'; +// ignore_for_file: avoid_print + +class SchedulePage extends StatefulWidget { + const SchedulePage({super.key}); + + @override + State createState() => _SchedulePageState(); +} + +class _SchedulePageState extends State { + final CalendarFormat _calendarFormat = CalendarFormat.month; + DateTime _focusedDay = DateTime.now(); + DateTime? _selectedDay; + + // Data pesanan dari API + List> _scheduledOrders = []; + bool _isLoading = false; + String _errorMessage = ''; + + @override + void initState() { + super.initState(); + _selectedDay = _focusedDay; + _loadCalendarData(); + } + + // Fungsi untuk memformat angka bulan menjadi format dengan leading zero + String _formatMonth(int month) { + return month.toString().padLeft(2, '0'); + } + + // Fungsi untuk memuat data kalender dari API + Future _loadCalendarData() async { + if (mounted) { + setState(() { + _isLoading = true; + _errorMessage = ''; + }); + } + + try { + // Format bulan dan tahun sesuai kebutuhan API + final month = _formatMonth(_focusedDay.month); + final year = _focusedDay.year.toString(); + + print('DEBUG: Memuat data kalender untuk bulan $month tahun $year'); + final result = await ApiService.getTailorCalendar(month, year); + + if (mounted) { + setState(() { + _isLoading = false; + + if (result['success']) { + // Parse data dari API ke format yang dibutuhkan + // Data dari API berbentuk: {"month":4, "year":2025, "month_name":"April", "calendar":[...]} + final apiData = result['data'] as Map; + print( + 'DEBUG: Data kalender berhasil dimuat untuk ${apiData['month_name']} ${apiData['year']}'); + + final calendarData = apiData['calendar'] as List? ?? []; + print('DEBUG: Jumlah hari dalam kalender: ${calendarData.length}'); + + _scheduledOrders = []; + + // Proses setiap tanggal dalam kalender + for (var dayData in calendarData) { + final String dateString = dayData['date'] ?? ''; + final bookings = dayData['bookings'] as List? ?? []; + + // Jika ada booking pada tanggal tersebut + if (bookings.isNotEmpty) { + print( + 'DEBUG: Terdapat ${bookings.length} booking pada tanggal $dateString'); + } + + for (var booking in bookings) { + final DateTime bookingDate = DateTime.parse(dateString); + + _scheduledOrders.add({ + 'date': bookingDate, + 'orderCode': booking['id']?.toString() ?? '', + 'customerName': booking['customer_name'] ?? '', + 'service': booking['service_type'] ?? '', + 'status': booking['status'] ?? '', + 'id': booking['id']?.toString() ?? '', + }); + } + } + + print( + 'DEBUG: Total booking yang ditampilkan: ${_scheduledOrders.length}'); + _errorMessage = ''; + } else { + _scheduledOrders = []; + _errorMessage = result['message'] ?? 'Gagal memuat data kalender'; + print('DEBUG: Gagal memuat data kalender: $_errorMessage'); + } + }); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + _errorMessage = 'Terjadi kesalahan: $e'; + _scheduledOrders = []; + }); + } + print('ERROR: Gagal memuat data kalender: $e'); + } + } + + // Helper untuk menampilkan marker pada kalender + List> _getEventsForDay(DateTime day) { + return _scheduledOrders.where((order) { + return isSameDay(order['date'] as DateTime, day); + }).toList(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey.shade50, + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFF1A2552)), + onPressed: () => Navigator.pop(context), + ), + title: const Text( + 'Kalender', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + centerTitle: false, + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.white, + actions: [ + IconButton( + icon: const Icon(Icons.refresh, color: Color(0xFF1A2552)), + onPressed: _loadCalendarData, + ), + ], + ), + body: Column( + children: [ + _buildCalendar(), + if (_isLoading) + const Expanded( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircularProgressIndicator(), + SizedBox(height: 16), + Text( + 'Memuat data kalender...', + style: TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + ], + ), + ), + ) + else if (_errorMessage.isNotEmpty) + Expanded( + child: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.error_outline, + size: 48, + color: Colors.red.shade300, + ), + const SizedBox(height: 16), + Text( + _errorMessage, + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.red.shade700, + fontSize: 16, + ), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadCalendarData, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + ), + child: const Text('Coba Lagi'), + ), + ], + ), + ), + ), + ) + else + Expanded( + child: _buildScheduleList(), + ), + ], + ), + ); + } + + Widget _buildCalendar() { + return Container( + margin: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(12), + ), + child: TableCalendar( + firstDay: DateTime.utc(2020, 1, 1), + lastDay: DateTime.utc(2030, 12, 31), + focusedDay: _focusedDay, + calendarFormat: _calendarFormat, + headerStyle: const HeaderStyle( + titleCentered: true, + formatButtonVisible: false, + leftChevronIcon: + Icon(Icons.chevron_left, color: Color(0xFF1A2552)), + rightChevronIcon: + Icon(Icons.chevron_right, color: Color(0xFF1A2552)), + titleTextStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + headerPadding: EdgeInsets.symmetric(vertical: 12), + headerMargin: EdgeInsets.only(bottom: 8), + ), + calendarStyle: const CalendarStyle( + outsideDaysVisible: false, + defaultTextStyle: TextStyle(color: Colors.black87), + weekendTextStyle: TextStyle(color: Colors.black87), + todayDecoration: BoxDecoration( + color: Color(0xFF1A2552), + shape: BoxShape.circle, + ), + selectedDecoration: BoxDecoration( + color: Color(0xFF1A2552), + shape: BoxShape.circle, + ), + cellMargin: EdgeInsets.all(4), + markersMaxCount: 3, + markerDecoration: BoxDecoration( + color: Colors.orange, + shape: BoxShape.circle, + ), + markerSize: 6.0, + ), + daysOfWeekStyle: const DaysOfWeekStyle( + weekdayStyle: TextStyle(color: Colors.black87, fontSize: 12), + weekendStyle: TextStyle(color: Colors.black87, fontSize: 12), + ), + selectedDayPredicate: (day) { + return isSameDay(_selectedDay, day); + }, + onDaySelected: (selectedDay, focusedDay) { + setState(() { + _selectedDay = selectedDay; + _focusedDay = focusedDay; + }); + }, + onPageChanged: (focusedDay) { + setState(() { + _focusedDay = focusedDay; + }); + + // Muat data baru jika bulan berubah + if (_focusedDay.month != _selectedDay?.month || + _focusedDay.year != _selectedDay?.year) { + _loadCalendarData(); + } + }, + eventLoader: (day) { + // Menandai hari yang memiliki pesanan + final events = _getEventsForDay(day); + return events.isNotEmpty + ? [1] + : []; // Cukup mengembalikan list dengan 1 item jika ada event + }, + ), + ); + } + + Widget _buildScheduleList() { + if (_selectedDay == null) return Container(); + + // Filter pesanan berdasarkan tanggal yang dipilih + final ordersForSelectedDay = _scheduledOrders.where((order) { + return isSameDay(order['date'], _selectedDay); + }).toList(); + + if (ordersForSelectedDay.isEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.event_busy, + size: 64, + color: Colors.grey.shade400, + ), + const SizedBox(height: 16), + Text( + 'Tidak ada jadwal untuk tanggal ini', + style: TextStyle( + fontSize: 16, + color: Colors.grey.shade600, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 8), + Text( + 'Pilih tanggal lain atau tambahkan pesanan baru', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade500, + ), + ), + ], + ), + ); + } + + return ListView.builder( + padding: const EdgeInsets.all(16), + itemCount: ordersForSelectedDay.length, + itemBuilder: (context, index) { + final order = ordersForSelectedDay[index]; + return _buildScheduleItem(order); + }, + ); + } + + Widget _buildScheduleItem(Map order) { + final formattedDate = DateFormat('d MMM yyyy').format(order['date']); + + // Tentukan warna berdasarkan status + Color statusColor = Colors.orange; + String statusText = order['status'].toString().toUpperCase(); + + if (order['status'] == 'diterima') { + statusColor = Colors.blue; + } else if (order['status'] == 'diproses') { + statusColor = Colors.orange; + } else if (order['status'] == 'selesai') { + statusColor = Colors.green; + } else if (order['status'] == 'dibatalkan') { + statusColor = Colors.red; + } else if (order['status'] == 'reservasi') { + statusColor = Colors.purple; + statusText = 'RESERVASI'; + } + + return Card( + margin: const EdgeInsets.only(bottom: 12), + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + const Icon(Icons.event, size: 16, color: Color(0xFF1A2552)), + const SizedBox(width: 4), + Text( + formattedDate, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + Container( + padding: + const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + decoration: BoxDecoration( + color: statusColor.withOpacity(0.2), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + statusText, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: statusColor, + ), + ), + ), + ], + ), + const Divider(height: 16), + Row( + children: [ + const Text( + 'Kode Pesanan: ', + style: TextStyle( + fontSize: 14, + color: Colors.black87, + ), + ), + Text( + '#${order['orderCode']}', + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon(Icons.person_outline, + size: 14, color: Colors.grey), + const SizedBox(width: 4), + Flexible( + child: Text( + order['customerName'], + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + const SizedBox(height: 4), + Row( + children: [ + const Icon(Icons.design_services_outlined, + size: 14, color: Colors.grey), + const SizedBox(width: 4), + Flexible( + child: Text( + order['service'], + style: const TextStyle( + fontSize: 12, + color: Colors.black87, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ], + ), + ), + IconButton( + icon: const Icon(Icons.arrow_forward_ios, + size: 16, color: Color(0xFF1A2552)), + onPressed: () { + // Navigasi ke detail pesanan + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => OrderDetailPage(orderId: order['id']), + // ), + // ).then((_) => _loadCalendarData()); + }, + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/TA_android/lib/pages/tailor/wallet/add_bank_account_page.dart b/TA_android/lib/pages/tailor/wallet/add_bank_account_page.dart new file mode 100644 index 0000000..50ae804 --- /dev/null +++ b/TA_android/lib/pages/tailor/wallet/add_bank_account_page.dart @@ -0,0 +1,508 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import '../../../core/controllers/wallet_wd_controller.dart'; +import '../../../core/widgets/custom_text_field.dart'; + +class AddBankAccountPage extends StatefulWidget { + const AddBankAccountPage({super.key}); + + @override + State createState() => _AddBankAccountPageState(); +} + +class _AddBankAccountPageState extends State { + final _formKey = GlobalKey(); + final _bankNameController = TextEditingController(); + final _accountNumberController = TextEditingController(); + final _accountHolderNameController = TextEditingController(); + bool _isLoading = false; + + // Daftar bank yang tersedia + final List _availableBanks = [ + 'BCA', + 'Mandiri', + 'BNI', + 'BRI', + 'CIMB Niaga', + // 'Permata', + // 'Danamon', + 'BTN', + // 'Bank Jago', + // 'Bank Neo Commerce', + 'Dana', + 'OVO', + 'GoPay', + ]; + + String? _selectedBank; + + @override + void dispose() { + _bankNameController.dispose(); + _accountNumberController.dispose(); + _accountHolderNameController.dispose(); + super.dispose(); + } + + void _showErrorDialog(String message) { + showGeneralDialog( + context: context, + barrierDismissible: false, + barrierLabel: 'Error Dialog', + transitionDuration: const Duration(milliseconds: 300), + pageBuilder: (context, anim1, anim2) => Container(), + transitionBuilder: (context, animation, secondaryAnimation, child) { + final curvedAnimation = CurvedAnimation( + parent: animation, + curve: Curves.easeOutBack, + ); + + return ScaleTransition( + scale: Tween(begin: 0.5, end: 1.0).animate(curvedAnimation), + child: FadeTransition( + opacity: Tween(begin: 0.0, end: 1.0).animate(curvedAnimation), + child: Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 1, + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Icon error dengan animasi + Container( + height: 80, + width: 80, + margin: const EdgeInsets.only(bottom: 15), + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.error_outline, + color: Colors.red, + size: 60, + ), + ), + + // Teks error + const Text( + 'Error', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + + const SizedBox(height: 15), + + // Pesan error + Text( + message, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Colors.grey.shade700, + ), + ), + + const SizedBox(height: 25), + + // Tombol OK + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () => Navigator.pop(context), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: const Text( + 'OK', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + void _showSuccessDialog(String message) { + showGeneralDialog( + context: context, + barrierDismissible: false, + barrierLabel: 'Success Dialog', + transitionDuration: const Duration(milliseconds: 300), + pageBuilder: (context, anim1, anim2) => Container(), + transitionBuilder: (context, animation, secondaryAnimation, child) { + final curvedAnimation = CurvedAnimation( + parent: animation, + curve: Curves.easeOutBack, + ); + + return ScaleTransition( + scale: Tween(begin: 0.5, end: 1.0).animate(curvedAnimation), + child: FadeTransition( + opacity: Tween(begin: 0.0, end: 1.0).animate(curvedAnimation), + child: Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 1, + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Icon success dengan animasi + Container( + height: 80, + width: 80, + margin: const EdgeInsets.only(bottom: 15), + decoration: BoxDecoration( + color: Colors.green.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.check_circle, + color: Colors.green, + size: 60, + ), + ), + + // Teks sukses + const Text( + 'Sukses', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + + const SizedBox(height: 15), + + // Pesan sukses + Text( + message, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Colors.grey.shade700, + ), + ), + + const SizedBox(height: 25), + + // Tombol OK + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); // Close dialog + Navigator.pop(context); // Back to previous page + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: const Text( + 'OK', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + Future _submitForm() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _isLoading = true); + + try { + final walletController = Provider.of(context, listen: false); + + final result = await walletController.registerBankAccount( + bankName: _selectedBank ?? _bankNameController.text, + accountNumber: _accountNumberController.text, + accountHolderName: _accountHolderNameController.text, + ); + + if (result['success']) { + // Refresh data sebelum menampilkan dialog sukses + await walletController.fetchBankAccounts(); + _showSuccessDialog(result['message'] ?? 'Akun bank berhasil didaftarkan'); + } else { + _showErrorDialog(result['message'] ?? 'Gagal mendaftarkan akun bank'); + } + } catch (e) { + _showErrorDialog('Terjadi kesalahan: $e'); + } finally { + setState(() => _isLoading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text( + 'Tambah Akun Bank', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + elevation: 0, + iconTheme: const IconThemeData(color: Color(0xFF1A2552)), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Info Card + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.info_outline, + color: Colors.blue.shade700, + size: 20, + ), + const SizedBox(width: 8), + Text( + 'Informasi', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.blue.shade700, + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + 'Pastikan data yang Anda masukkan sesuai dengan buku tabungan/rekening bank Anda. Akun bank akan diverifikasi oleh admin sebelum dapat digunakan untuk penarikan dana.', + style: TextStyle( + fontSize: 12, + color: Colors.blue.shade700, + ), + ), + ], + ), + ), + + const SizedBox(height: 24), + + // Nama Bank + const Text( + 'Nama Bank', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade300), + ), + child: DropdownButtonHideUnderline( + child: DropdownButtonFormField( + value: _selectedBank, + decoration: const InputDecoration( + hintText: 'Pilih Bank', + contentPadding: EdgeInsets.symmetric(horizontal: 16), + border: InputBorder.none, + ), + items: _availableBanks.map((String bank) { + return DropdownMenuItem( + value: bank, + child: Text(bank), + ); + }).toList(), + onChanged: (String? newValue) { + setState(() { + _selectedBank = newValue; + _bankNameController.text = newValue ?? ''; + }); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Pilih bank terlebih dahulu'; + } + return null; + }, + ), + ), + ), + + const SizedBox(height: 24), + + // Nomor Rekening + const Text( + 'Nomor Rekening', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + CustomTextField( + controller: _accountNumberController, + labelText: 'Masukkan nomor rekening', + keyboardType: TextInputType.number, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Nomor rekening tidak boleh kosong'; + } + if (!RegExp(r'^\d+$').hasMatch(value)) { + return 'Nomor rekening hanya boleh berisi angka'; + } + return null; + }, + ), + + const SizedBox(height: 24), + + // Nama Pemilik Rekening + const Text( + 'Nama Pemilik Rekening', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + CustomTextField( + controller: _accountHolderNameController, + labelText: 'Masukkan nama pemilik rekening', + textCapitalization: TextCapitalization.words, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Nama pemilik rekening tidak boleh kosong'; + } + return null; + }, + ), + + const SizedBox(height: 24), + + // Tombol Submit + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isLoading ? null : _submitForm, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: _isLoading + ? const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + : const Text( + 'Daftarkan Akun Bank', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/TA_android/lib/pages/tailor/wallet/wallet_history_page.dart b/TA_android/lib/pages/tailor/wallet/wallet_history_page.dart new file mode 100644 index 0000000..615127a --- /dev/null +++ b/TA_android/lib/pages/tailor/wallet/wallet_history_page.dart @@ -0,0 +1,1062 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:provider/provider.dart'; +import '../../../core/controllers/wallet_wd_controller.dart'; +import '../../../core/models/wallet_transaction_model.dart'; +import 'dart:developer' as developer; +import '../../../core/services/api_service.dart'; +import '../../../core/services/wallet_wd_service.dart'; +import '../../../core/utils/url_helper.dart'; +import '../../../core/utils/app_routes.dart'; +import 'package:cached_network_image/cached_network_image.dart'; + +class WalletHistoryPage extends StatefulWidget { + const WalletHistoryPage({super.key}); + + @override + State createState() => _WalletHistoryPageState(); +} + +class _WalletHistoryPageState extends State { + // Format currency + final currencyFormat = NumberFormat.currency( + locale: 'id', + symbol: 'Rp ', + decimalDigits: 0, + ); + + // Format date + late final DateFormat dateFormat; + bool _initialized = false; + final bool _isDebugMode = false; // Nonaktifkan mode debug untuk user + String _selectedStatusFilter = 'all'; // Default filter: semua status + bool _isBalanceExpanded = false; // State untuk panel saldo (collapsed by default) + + @override + void initState() { + super.initState(); + _initializeDateFormatting(); + } + + Future _initializeDateFormatting() async { + await initializeDateFormatting('id_ID', null); + setState(() { + dateFormat = DateFormat.yMMMMd('id_ID').add_Hm(); + _initialized = true; + }); + _loadData(); + } + + Future _loadData() async { + if (!_initialized || !mounted) return; + + try { + _logInfo('Memuat data wallet...'); + final controller = Provider.of(context, listen: false); + await controller.fetchWalletInfo(); + await controller.fetchBankAccounts(); + await controller.fetchWithdrawalHistory(); // Tanpa filter + _logInfo('Selesai memuat data wallet'); + } catch (e) { + _logInfo('Error memuat data wallet: $e'); + } + } + + // Metode untuk memuat data penarikan berdasarkan status + Future _loadWithdrawalWithStatus(String status) async { + if (!_initialized || !mounted) return; + + try { + _logInfo('Memuat withdrawal dengan status: $status'); + final controller = Provider.of(context, listen: false); + await controller.fetchWithdrawalHistory(status: status); + _logInfo('Selesai memuat withdrawal dengan status: $status'); + } catch (e) { + _logInfo('Error memuat withdrawal: $e'); + } + } + + // Fungsi untuk membantu debugging wallet service + Future _debugWalletService() async { + if (!_isDebugMode) return; + + try { + _logInfo('====== DEBUG WALLET SERVICE ======'); + + // Debug token + final token = await ApiService.getToken(); + _logInfo('Token autentikasi: ${token != null ? 'Ada (${token.substring(0, 10)}...)' : 'Null'}'); + + // Debug base URL + final baseUrl = UrlHelper.baseUrl; + _logInfo('Base URL API: $baseUrl'); + + // Debug endpoint penarikan + final withdrawalEndpoint = '$baseUrl/withdrawals'; + _logInfo('Endpoint withdrawal: $withdrawalEndpoint'); + + _logInfo('====== END DEBUG WALLET SERVICE ======'); + } catch (e, stackTrace) { + _logError('Error saat debugging wallet service', e, stackTrace); + } + } + + // Fungsi untuk debug informasi wallet + void _debugWalletInfo(WalletWDController controller) { + if (!_isDebugMode) return; + + _logInfo('====== DEBUG WALLET INFO ======'); + final walletInfo = controller.walletInfo; + + if (walletInfo == null) { + _logInfo('Wallet Info: null'); + } else { + _logInfo('Wallet Balance: ${walletInfo.balance}'); + _logInfo('Transactions count: ${walletInfo.transactions.length}'); + + if (walletInfo.transactions.isNotEmpty) { + _logInfo('Latest transaction: ${walletInfo.transactions.first.description} - ${walletInfo.transactions.first.amount}'); + } + } + + _logInfo('Error message: ${controller.errorMessage}'); + _logInfo('====== END DEBUG WALLET INFO ======'); + } + + // Fungsi untuk debug riwayat penarikan + void _debugWithdrawalHistory(WalletWDController controller) { + if (!_isDebugMode) return; + + _logInfo('====== DEBUG WITHDRAWAL HISTORY ======'); + final withdrawals = controller.withdrawalHistory; + + _logInfo('Withdrawal count: ${withdrawals.length}'); + + if (withdrawals.isEmpty) { + _logInfo('Tidak ada data penarikan.'); + } else { + for (int i = 0; i < withdrawals.length; i++) { + final withdrawal = withdrawals[i]; + _logInfo('Withdrawal #${i + 1}:'); + _logInfo('- amount: ${withdrawal['amount']}'); + _logInfo('- status: ${withdrawal['status']}'); + _logInfo('- created_at: ${withdrawal['created_at']}'); + + final bankAccount = withdrawal['bank_account']; + _logInfo('- bank: ${bankAccount['bank_name']}'); + _logInfo('- account: ${bankAccount['account_number']}'); + } + } + + _logInfo('Error message: ${controller.errorMessage}'); + _logInfo('====== END DEBUG WITHDRAWAL HISTORY ======'); + } + + // Fungsi helper untuk logging + void _logInfo(String message) { + if (_isDebugMode && mounted) { + // Tambahkan prefix untuk membedakan log dari halaman ini + developer.log('[WALLET HISTORY] $message', name: 'TailorHub'); + } + } + + // Metode ini tidak akan melakukan apa-apa di mode produksi + // tapi tetap disediakan untuk memudahkan debugging jika diperlukan + void _logError(String message, dynamic error, StackTrace? stackTrace) { + if (_isDebugMode) { + developer.log( + '[WALLET HISTORY ERROR] $message: $error', + name: 'TailorHub', + error: error, + stackTrace: stackTrace, + ); + } + } + + @override + Widget build(BuildContext context) { + if (!_initialized) { + return const Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + } + + return DefaultTabController( + length: 2, + child: Builder( + builder: (BuildContext context) { + final TabController tabController = DefaultTabController.of(context); + + // Tambahkan listener untuk tab aktif jika diperlukan + tabController.addListener(() { + // Jika diperlukan kode reaksi terhadap perubahan tab + }); + + return Scaffold( + appBar: AppBar( + title: const Text( + 'Riwayat Wallet', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + elevation: 0, + iconTheme: const IconThemeData(color: Color(0xFF1A2552)), + bottom: const TabBar( + labelColor: Color(0xFF1A2552), + unselectedLabelColor: Colors.grey, + indicatorColor: Color(0xFF1A2552), + tabs: [ + Tab(text: 'Transaksi'), + Tab(text: 'Penarikan'), + ], + ), + ), + body: Consumer( + builder: (context, walletController, child) { + if (walletController.isLoading) { + return const Center(child: CircularProgressIndicator()); + } + + if (walletController.errorMessage.isNotEmpty) { + _logInfo('Error dari controller: ${walletController.errorMessage}'); + + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.error_outline, size: 48, color: Colors.red), + const SizedBox(height: 16), + Text( + walletController.errorMessage, + textAlign: TextAlign.center, + style: const TextStyle(color: Colors.red), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadData, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + ), + child: const Text('Coba Lagi'), + ), + ], + ), + ); + } + + // Tambahkan widget Card untuk menampilkan informasi saldo + return Column( + children: [ + // Info Card - Informasi Saldo + if (walletController.walletInfo != null) + Container( + margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade300, width: 1), + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + setState(() { + _isBalanceExpanded = !_isBalanceExpanded; + }); + }, + borderRadius: BorderRadius.circular(8), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Informasi Saldo', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + Icon( + _isBalanceExpanded + ? Icons.keyboard_arrow_up + : Icons.keyboard_arrow_down, + color: const Color(0xFF1A2552), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(12.0, 0, 12.0, 12.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Total'), + Text( + currencyFormat.format(walletController.walletInfo!.getBalanceAsDouble()), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + // Detail saldo tertahan dan tersedia + if (_isBalanceExpanded) + Padding( + padding: const EdgeInsets.fromLTRB(12.0, 0, 12.0, 12.0), + child: Column( + children: [ + const Divider(), + const SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Saldo Tertahan'), + Text( + currencyFormat.format(walletController.walletInfo!.getPendingWithdrawalsAsDouble()), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.orange.shade700, + ), + ), + ], + ), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Saldo Tersedia'), + Text( + currencyFormat.format(walletController.walletInfo!.getAvailableBalanceAsDouble()), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.green.shade700, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + ), + + Expanded( + child: TabBarView( + children: [ + // Tab Transaksi + _buildTransactionsTab(walletController), + + // Tab Penarikan + _buildWithdrawalsTab(walletController), + ], + ), + ), + ], + ); + }, + ), + floatingActionButton: null, + ); + } + ), + ); + } + + Widget _buildTransactionsTab(WalletWDController walletController) { + final transactions = walletController.walletInfo?.transactions ?? []; + + if (transactions.isEmpty) { + _logInfo('Transactions tab: Data kosong'); + + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.account_balance_wallet_outlined, + size: 64, + color: Colors.grey.shade400, + ), + const SizedBox(height: 16), + Text( + 'Belum ada transaksi', + style: TextStyle( + fontSize: 16, + color: Colors.grey.shade600, + ), + ), + ], + ), + ); + } + + _logInfo('Transactions tab: Menampilkan ${transactions.length} transaksi'); + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: RefreshIndicator( + onRefresh: _loadData, + child: ListView.separated( + padding: const EdgeInsets.symmetric(vertical: 8), + itemCount: transactions.length, + separatorBuilder: (context, index) => const SizedBox(height: 12), + itemBuilder: (context, index) { + final transaction = transactions[index]; + return Card( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Colors.grey.shade300), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + children: [ + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: transaction.getTypeColor().withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon( + transaction.getTypeIcon(), + color: transaction.getTypeColor(), + size: 20, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + transaction.description, + style: const TextStyle( + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + dateFormat.format(DateTime.parse(transaction.createdAt)), + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + ], + ), + ), + Text( + '${transaction.type.toLowerCase() == 'credit' ? '+' : '-'} ${currencyFormat.format(transaction.getAmountAsDouble())}', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: transaction.getTypeColor(), + ), + ), + ], + ), + ), + ); + }, + ), + ), + ); + } + + Widget _buildWithdrawalsTab(WalletWDController walletController) { + final withdrawals = walletController.withdrawalHistory; + + // Widget untuk chip filter + Widget buildFilterChip(String label, String value) { + final isSelected = _selectedStatusFilter == value; + return InkWell( + onTap: () { + setState(() { + _selectedStatusFilter = value; + }); + if (value == 'all') { + _loadData(); + } else { + _loadWithdrawalWithStatus(value); + } + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: isSelected ? const Color(0xFF1A2552) : Colors.grey.shade200, + borderRadius: BorderRadius.circular(20), + ), + child: Text( + label, + style: TextStyle( + color: isSelected ? Colors.white : Colors.black87, + fontSize: 12, + fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, + ), + ), + ), + ); + } + + // Widget untuk filter status + Widget buildStatusFilter() { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade300, width: 1), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Filter Status:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + buildFilterChip('Semua', 'all'), + const SizedBox(width: 8), + buildFilterChip('Menunggu', 'pending'), + const SizedBox(width: 8), + buildFilterChip('Diproses', 'processing'), + const SizedBox(width: 8), + buildFilterChip('Selesai', 'completed'), + const SizedBox(width: 8), + buildFilterChip('Ditolak', 'rejected'), + ], + ), + ), + ], + ), + ), + ); + } + + if (withdrawals.isEmpty) { + _logInfo('Withdrawals tab: Data kosong'); + + return Column( + children: [ + // Tampilkan filter meskipun data kosong + buildStatusFilter(), + Expanded( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.account_balance_outlined, + size: 64, + color: Colors.grey.shade400, + ), + const SizedBox(height: 16), + Text( + 'Belum ada riwayat penarikan', + style: TextStyle( + fontSize: 16, + color: Colors.grey.shade600, + ), + ), + const SizedBox(height: 24), + // Tampilkan tombol untuk melakukan penarikan jika data kosong + ElevatedButton.icon( + onPressed: () async { + // Navigasi ke halaman penarikan dan tunggu hasil + final result = await Navigator.pushNamed(context, AppRoutes.withdrawal); + + // Jika hasil = true (penarikan berhasil), refresh data + if (result == true && mounted) { + _loadData(); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + icon: const Icon(Icons.account_balance_wallet), + label: const Text('Ajukan Penarikan Dana'), + ), + ], + ), + ), + ), + ], + ); + } + + _logInfo('Withdrawals tab: Menampilkan ${withdrawals.length} penarikan'); + + return Column( + children: [ + // Filter status + buildStatusFilter(), + // List penarikan + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: RefreshIndicator( + onRefresh: _loadData, + child: ListView.separated( + padding: const EdgeInsets.symmetric(vertical: 8.0), + itemCount: withdrawals.length, + separatorBuilder: (context, index) => const SizedBox(height: 12), + itemBuilder: (context, index) { + final withdrawal = withdrawals[index]; + final bankAccount = withdrawal['bank_account']; + final status = withdrawal['status'] as String; + final amount = double.parse(withdrawal['amount'].toString()); + final createdAt = DateTime.parse(withdrawal['created_at']); + final processedAt = withdrawal['processed_at'] != null + ? DateTime.parse(withdrawal['processed_at']) + : null; + final proofOfPayment = withdrawal['proof_of_payment']; + + // Warna status + final statusColor = walletController.getWithdrawalStatusColor(status); + final statusText = walletController.getWithdrawalStatusText(status); + + return Card( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Colors.grey.shade300), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Baris pertama: ID Penarikan & Status + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'ID #${withdrawal['id']}', + style: TextStyle( + fontSize: 14, + color: Colors.grey.shade600, + ), + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: statusColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + status.toLowerCase() == 'completed' + ? Icons.check_circle + : status.toLowerCase() == 'rejected' + ? Icons.cancel + : Icons.pending_actions, + size: 12, + color: statusColor, + ), + const SizedBox(width: 4), + Text( + statusText, + style: TextStyle( + fontSize: 12, + color: statusColor, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ], + ), + + const SizedBox(height: 8), + + // Bank information + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF1A2552).withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.account_balance, + color: Color(0xFF1A2552), + size: 24, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + bankAccount['bank_name'], + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(height: 4), + Text( + bankAccount['account_number'], + style: TextStyle( + color: Colors.grey.shade700, + ), + ), + Text( + bankAccount['account_holder_name'], + style: TextStyle( + color: Colors.grey.shade700, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ], + ), + ), + + const SizedBox(height: 12), + + // Amount information + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Jumlah Penarikan:', + style: TextStyle( + fontWeight: FontWeight.w500, + ), + ), + Text( + currencyFormat.format(amount), + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + + const SizedBox(height: 8), + const Divider(), + const SizedBox(height: 8), + + // Dates information + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Tanggal Pengajuan:', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 2), + Text( + dateFormat.format(createdAt), + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + ], + ), + ), + if (processedAt != null) + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Tanggal Proses:', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 2), + Text( + dateFormat.format(processedAt), + style: TextStyle( + fontSize: 12, + color: Colors.grey.shade600, + ), + ), + ], + ), + ), + ], + ), + + // Bukti pembayaran section (if available) + if (proofOfPayment != null) + Container( + margin: const EdgeInsets.only(top: 12), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.blue.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.receipt_long, + size: 16, + color: Colors.blue.shade700, + ), + const SizedBox(width: 8), + Text( + 'Bukti Pembayaran Tersedia', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.blue.shade700, + ), + ), + ], + ), + const SizedBox(height: 8), + OutlinedButton.icon( + onPressed: () { + // Buka halaman untuk melihat bukti pembayaran dengan URL lengkap + // Gunakan URL API langsung dan pastikan path lengkap termasuk direktori proof_of_payments/ + final String fullPath = proofOfPayment; + final paymentUrl = 'https://api.tailors.stuffly.my.id/storage/$fullPath'; + print('Opening payment proof image: $paymentUrl'); + _showPaymentProofDialog(context, paymentUrl); + }, + icon: const Icon(Icons.visibility), + label: const Text('Lihat Bukti Pembayaran'), + style: OutlinedButton.styleFrom( + foregroundColor: Colors.blue.shade700, + side: BorderSide(color: Colors.blue.shade300), + ), + ), + ], + ), + ), + + // Alasan penolakan + if (withdrawal['rejection_reason'] != null) + Container( + width: double.infinity, + margin: const EdgeInsets.only(top: 12), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.red.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.red.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.error_outline, + size: 16, + color: Colors.red.shade700, + ), + const SizedBox(width: 8), + Text( + 'Alasan Penolakan:', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.red.shade700, + ), + ), + ], + ), + const SizedBox(height: 4), + Text( + withdrawal['rejection_reason'], + style: TextStyle( + color: Colors.red.shade700, + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ), + ), + ), + ), + ], + ); + } + + // Metode untuk menampilkan bukti pembayaran dalam dialog + void _showPaymentProofDialog(BuildContext context, String imageUrl) { + showDialog( + context: context, + useSafeArea: true, + barrierDismissible: true, + builder: (BuildContext context) { + return Dialog.fullscreen( + child: Scaffold( + backgroundColor: Colors.black, + appBar: AppBar( + backgroundColor: Colors.black, + iconTheme: const IconThemeData(color: Colors.white), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.of(context).pop(), + ), + title: const Text( + 'Bukti Pembayaran', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + body: Stack( + children: [ + // Image viewer + Center( + child: InteractiveViewer( + minScale: 0.5, + maxScale: 3.0, + child: CachedNetworkImage( + imageUrl: imageUrl, + placeholder: (context, url) => const Center( + child: CircularProgressIndicator( + color: Colors.white, + ), + ), + errorWidget: (context, url, error) { + print('Error loading image: $error for URL: $url'); + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.error_outline, + color: Colors.red, + size: 64, + ), + const SizedBox(height: 16), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Text( + 'Gagal memuat gambar bukti pembayaran: ${error.toString()}', + textAlign: TextAlign.center, + style: const TextStyle(color: Colors.white), + ), + ), + const SizedBox(height: 16), + ElevatedButton.icon( + icon: const Icon(Icons.refresh), + label: const Text('Coba Lagi'), + onPressed: () { + Navigator.of(context).pop(); + // Re-show the dialog after a short delay + Future.delayed(const Duration(milliseconds: 300), () { + _showPaymentProofDialog(context, imageUrl); + }); + }, + ), + ], + ); + }, + fit: BoxFit.contain, + fadeInDuration: const Duration(milliseconds: 200), + ), + ), + ), + + // Bottom info (optional - info tentang bukti pembayaran) + Positioned( + left: 0, + right: 0, + bottom: 0, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + Colors.black.withOpacity(0.7), + Colors.transparent, + ], + ), + ), + child: const Text( + 'Bukti pembayaran penarikan dana', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } +} \ No newline at end of file diff --git a/TA_android/lib/pages/tailor/wallet/withdrawal_page.dart b/TA_android/lib/pages/tailor/wallet/withdrawal_page.dart new file mode 100644 index 0000000..d654623 --- /dev/null +++ b/TA_android/lib/pages/tailor/wallet/withdrawal_page.dart @@ -0,0 +1,922 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import '../../../core/controllers/wallet_wd_controller.dart'; +import '../../../core/models/wallet_model.dart'; +import '../../../core/widgets/custom_text_field.dart'; +import '../../../core/utils/app_routes.dart'; + +class WithdrawalPage extends StatefulWidget { + const WithdrawalPage({super.key}); + + @override + State createState() => _WithdrawalPageState(); +} + +class _WithdrawalPageState extends State { + final _formKey = GlobalKey(); + final _amountController = TextEditingController(); + BankAccount? _selectedBankAccount; + bool _isLoading = false; + + // Format currency + final currencyFormat = NumberFormat.currency( + locale: 'id', + symbol: 'Rp ', + decimalDigits: 0, + ); + + @override + void initState() { + super.initState(); + _loadBankAccounts(); + } + + @override + void dispose() { + _amountController.dispose(); + super.dispose(); + } + + Future _loadBankAccounts() async { + final walletController = Provider.of(context, listen: false); + await walletController.fetchBankAccounts(); + } + + void _showErrorDialog(String message) { + showGeneralDialog( + context: context, + barrierDismissible: false, + barrierLabel: 'Error Dialog', + transitionDuration: const Duration(milliseconds: 300), + pageBuilder: (context, anim1, anim2) => Container(), + transitionBuilder: (context, animation, secondaryAnimation, child) { + final curvedAnimation = CurvedAnimation( + parent: animation, + curve: Curves.easeOutBack, + ); + + return ScaleTransition( + scale: Tween(begin: 0.5, end: 1.0).animate(curvedAnimation), + child: FadeTransition( + opacity: Tween(begin: 0.0, end: 1.0).animate(curvedAnimation), + child: Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 1, + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Icon error dengan animasi + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: const Duration(milliseconds: 600), + curve: Curves.elasticOut, + builder: (context, value, child) { + return Transform.scale( + scale: value, + child: Container( + height: 80, + width: 80, + margin: const EdgeInsets.only(bottom: 15), + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.error_outline, + color: Colors.red, + size: 60, + ), + ), + ); + } + ), + + // Teks error + const Text( + 'Error', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + + const SizedBox(height: 15), + + // Pesan error + Text( + message, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Colors.grey.shade700, + ), + ), + + const SizedBox(height: 25), + + // Tombol OK + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () => Navigator.pop(context), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: const Text( + 'OK', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + void _showSuccessDialog(String message) { + showGeneralDialog( + context: context, + barrierDismissible: false, + barrierLabel: 'Success Dialog', + transitionDuration: const Duration(milliseconds: 300), + pageBuilder: (context, anim1, anim2) => Container(), + transitionBuilder: (context, animation, secondaryAnimation, child) { + final curvedAnimation = CurvedAnimation( + parent: animation, + curve: Curves.easeOutBack, + ); + + return ScaleTransition( + scale: Tween(begin: 0.5, end: 1.0).animate(curvedAnimation), + child: FadeTransition( + opacity: Tween(begin: 0.0, end: 1.0).animate(curvedAnimation), + child: Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + spreadRadius: 1, + blurRadius: 5, + offset: const Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Icon success dengan animasi + TweenAnimationBuilder( + tween: Tween(begin: 0.0, end: 1.0), + duration: const Duration(milliseconds: 600), + curve: Curves.elasticOut, + builder: (context, value, child) { + return Transform.scale( + scale: value, + child: Container( + height: 80, + width: 80, + margin: const EdgeInsets.only(bottom: 15), + decoration: BoxDecoration( + color: Colors.green.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.check_circle, + color: Colors.green, + size: 60, + ), + ), + ); + } + ), + + // Teks sukses + const Text( + 'Sukses', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + + const SizedBox(height: 15), + + // Pesan sukses + Text( + message, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: Colors.grey.shade700, + ), + ), + + const SizedBox(height: 25), + + // Tombol OK + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + // Refresh data dengan force rebuild widget + setState(() {}); + + // Tutup dialog + Navigator.pop(context); + + // Kembali ke halaman sebelumnya + Navigator.of(context).pop(true); // Pop dengan result=true agar halaman sebelumnya tahu harus refresh + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 15), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: const Text( + 'OK', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ), + ); + }, + ); + } + + Future _submitWithdrawal() async { + if (!_formKey.currentState!.validate()) return; + if (_selectedBankAccount == null) { + _showErrorDialog('Silakan pilih akun bank terlebih dahulu'); + return; + } + + setState(() => _isLoading = true); + + try { + final amount = double.parse(_amountController.text.replaceAll(RegExp(r'[^0-9]'), '')); + final walletController = Provider.of(context, listen: false); + + final result = await walletController.requestWithdrawal( + bankAccountId: _selectedBankAccount!.id, + amount: amount, + ); + + if (result['success']) { + _showSuccessDialog(result['message'] ?? 'Permintaan penarikan berhasil diajukan'); + } else { + _showErrorDialog(result['message'] ?? 'Gagal mengajukan penarikan'); + } + } catch (e) { + _showErrorDialog('Terjadi kesalahan: $e'); + } finally { + setState(() => _isLoading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text( + 'Penarikan Dana', + style: TextStyle( + color: Color(0xFF1A2552), + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + elevation: 0, + iconTheme: const IconThemeData(color: Color(0xFF1A2552)), + ), + body: Consumer( + builder: (context, walletController, child) { + if (walletController.isLoading) { + return const Center(child: CircularProgressIndicator()); + } + + if (walletController.errorMessage.isNotEmpty) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.error_outline, size: 48, color: Colors.red), + const SizedBox(height: 16), + Text( + walletController.errorMessage, + textAlign: TextAlign.center, + style: const TextStyle(color: Colors.red), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadBankAccounts, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + ), + child: const Text('Coba Lagi'), + ), + ], + ), + ); + } + + final bankAccounts = walletController.bankAccounts; + final walletInfo = walletController.walletInfo; + final walletBalance = walletInfo?.getBalanceAsDouble() ?? 0.0; + final pendingWithdrawals = walletInfo?.getPendingWithdrawalsAsDouble() ?? 0.0; + final availableBalance = walletInfo?.getAvailableBalanceAsDouble() ?? 0.0; + + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Saldo Wallet + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFF1A2552).withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Saldo Total + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Total Saldo', + style: TextStyle( + fontSize: 14, + color: Color(0xFF1A2552), + ), + ), + Text( + currencyFormat.format(walletBalance), + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ], + ), + const Divider(height: 16), + // Saldo Ditahan + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Saldo Ditahan', + style: TextStyle( + fontSize: 14, + color: Colors.orange, + ), + ), + Text( + currencyFormat.format(pendingWithdrawals), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.orange, + ), + ), + ], + ), + const SizedBox(height: 16), + // Saldo Tersedia + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Saldo Tersedia', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + Text( + currencyFormat.format(availableBalance), + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Color(0xFF34A853), + ), + ), + ], + ), + ], + ), + ), + + const SizedBox(height: 24), + + // Header dengan judul dan tombol tambah + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Pilih Bank', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + ElevatedButton.icon( + onPressed: () { + Navigator.pushNamed(context, AppRoutes.addBankAccount); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + icon: const Icon(Icons.add, size: 16), + label: const Text('Tambah Bank'), + ), + ], + ), + const SizedBox(height: 8), + + if (bankAccounts.isEmpty) + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.orange.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.orange.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.account_balance_wallet_outlined, + color: Colors.orange.shade800, + size: 20, + ), + const SizedBox(width: 8), + Text( + 'Belum ada akun bank', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.orange.shade800, + ), + ), + ], + ), + const SizedBox(height: 8), + const Text( + 'Tambahkan akun bank untuk melakukan penarikan dana', + style: TextStyle( + fontSize: 12, + color: Colors.black87, + ), + ), + ], + ), + ) + else + Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(12), + ), + child: ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: bankAccounts.length, + separatorBuilder: (context, index) => Divider( + height: 1, + color: Colors.grey.shade300, + ), + itemBuilder: (context, index) { + final bank = bankAccounts[index]; + final isSelected = bank == _selectedBankAccount; + final bankIcon = _getBankIcon(bank.bankName); + + if (bank.status.toLowerCase() != 'active') { + return InkWell( + onTap: bank.status.toLowerCase() == 'rejected' ? () { + _showRejectionReasonDialog(bank); + } : null, + child: ListTile( + leading: CircleAvatar( + backgroundColor: Colors.grey.shade200, + child: bankIcon, + ), + title: Text( + bank.bankName, + style: const TextStyle( + fontWeight: FontWeight.w500, + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('${bank.accountNumber} • ${bank.accountHolderName}'), + const SizedBox(height: 4), + Row( + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: bank.getStatusColor().withOpacity(0.1), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + bank.getStatusText(), + style: TextStyle( + fontSize: 12, + color: bank.getStatusColor(), + ), + ), + ), + if (bank.status.toLowerCase() == 'rejected') + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text( + 'Lihat detail', + style: TextStyle( + fontSize: 12, + color: Colors.blue.shade700, + decoration: TextDecoration.underline, + ), + ), + ), + ], + ), + ], + ), + enabled: false, + ), + ); + } + + return InkWell( + onTap: () { + setState(() => _selectedBankAccount = bank); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: isSelected + ? Border.all(color: const Color(0xFF1A2552), width: 2) + : null, + color: isSelected + ? const Color(0xFF1A2552).withOpacity(0.05) + : null, + ), + child: ListTile( + leading: CircleAvatar( + radius: 16, + backgroundColor: const Color(0xFF1A2552).withOpacity(0.1), + child: bankIcon, + ), + title: Text( + bank.bankName, + style: TextStyle( + fontWeight: FontWeight.w500, + color: isSelected + ? const Color(0xFF1A2552) + : Colors.black87, + ), + ), + subtitle: Text( + '${bank.accountNumber} • ${bank.accountHolderName}', + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + trailing: isSelected + ? const Icon( + Icons.check_circle, + color: Color(0xFF1A2552), + ) + : null, + ), + ), + ); + }, + ), + ), + + const SizedBox(height: 24), + + // Nominal Penarikan + const Text( + 'Nominal Penarikan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + CustomTextField( + controller: _amountController, + labelText: 'Masukkan nominal', + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + TextInputFormatter.withFunction((oldValue, newValue) { + if (newValue.text.isEmpty) return newValue; + final number = int.parse(newValue.text); + final formatted = currencyFormat.format(number); + return TextEditingValue( + text: formatted, + selection: TextSelection.collapsed(offset: formatted.length), + ); + }), + ], + validator: (value) { + if (value == null || value.isEmpty) { + return 'Nominal tidak boleh kosong'; + } + final amount = double.parse(value.replaceAll(RegExp(r'[^0-9]'), '')); + if (amount < 10000) { + return 'Minimal penarikan Rp 10.000'; + } + if (amount > availableBalance) { + return 'Saldo tersedia tidak mencukupi'; + } + return null; + }, + ), + + const SizedBox(height: 24), + + // Tombol Submit + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isLoading ? null : _submitWithdrawal, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A2552), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: _isLoading + ? const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + : const Text( + 'Ajukan Penarikan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ), + ), + ); + }, + ), + ); + } + + // Helper method untuk mendapatkan icon bank berdasarkan nama bank + Widget _getBankIcon(String bankName) { + switch (bankName.toUpperCase()) { + case 'BCA': + return const Icon(Icons.account_balance, size: 16, color: Color(0xFF1A2552)); + case 'MANDIRI': + return const Icon(Icons.account_balance, size: 16, color: Color(0xFF1A2552)); + case 'BNI': + return const Icon(Icons.account_balance, size: 16, color: Color(0xFF1A2552)); + case 'BRI': + return const Icon(Icons.account_balance, size: 16, color: Color(0xFF1A2552)); + default: + return const Icon(Icons.account_balance, size: 16, color: Color(0xFF1A2552)); + } + } + + void _showRejectionReasonDialog(BankAccount bank) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.cancel_outlined, + color: Colors.red.shade700, + size: 24, + ), + const SizedBox(width: 8), + const Expanded( + child: Text( + 'Rekening Bank Ditolak', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Text( + 'Bank:', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + const SizedBox(width: 8), + Text( + bank.bankName, + style: const TextStyle(fontSize: 14), + ), + ], + ), + const SizedBox(height: 4), + Row( + children: [ + const Text( + 'Nomor:', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + const SizedBox(width: 8), + Text( + bank.accountNumber, + style: const TextStyle(fontSize: 14), + ), + ], + ), + const SizedBox(height: 4), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Pemilik:', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + bank.accountHolderName, + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + ], + ), + ), + ], + ), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Alasan Penolakan:', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + color: Color(0xFF1A2552), + ), + ), + const SizedBox(height: 8), + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.red.shade50, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.red.shade100), + ), + child: Text( + bank.rejectionReason ?? + 'Data rekening tidak valid. Silakan periksa kembali data yang Anda masukkan.', + style: TextStyle( + fontSize: 14, + color: Colors.red.shade800, + ), + ), + ), + const SizedBox(height: 16), + const Text( + 'Silakan daftarkan rekening bank baru untuk penarikan dana.', + style: TextStyle( + fontSize: 13, + fontStyle: FontStyle.italic, + color: Colors.grey, + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Tutup'), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/TA_android/linux/.gitignore b/TA_android/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/TA_android/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/TA_android/linux/CMakeLists.txt b/TA_android/linux/CMakeLists.txt new file mode 100644 index 0000000..ea2d013 --- /dev/null +++ b/TA_android/linux/CMakeLists.txt @@ -0,0 +1,145 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "tailorhub") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.tailorhub") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/TA_android/linux/flutter/CMakeLists.txt b/TA_android/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/TA_android/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/TA_android/linux/flutter/generated_plugin_registrant.cc b/TA_android/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..7299b5c --- /dev/null +++ b/TA_android/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/TA_android/linux/flutter/generated_plugin_registrant.h b/TA_android/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/TA_android/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/TA_android/linux/flutter/generated_plugins.cmake b/TA_android/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..786ff5c --- /dev/null +++ b/TA_android/linux/flutter/generated_plugins.cmake @@ -0,0 +1,25 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/TA_android/linux/main.cc b/TA_android/linux/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/TA_android/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/TA_android/linux/my_application.cc b/TA_android/linux/my_application.cc new file mode 100644 index 0000000..dd24c51 --- /dev/null +++ b/TA_android/linux/my_application.cc @@ -0,0 +1,124 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "tailorhub"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "tailorhub"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/TA_android/linux/my_application.h b/TA_android/linux/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/TA_android/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/TA_android/linux/runner/CMakeLists.txt b/TA_android/linux/runner/CMakeLists.txt new file mode 100644 index 0000000..e97dabc --- /dev/null +++ b/TA_android/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/TA_android/linux/runner/main.cc b/TA_android/linux/runner/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/TA_android/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/TA_android/linux/runner/my_application.cc b/TA_android/linux/runner/my_application.cc new file mode 100644 index 0000000..42ac765 --- /dev/null +++ b/TA_android/linux/runner/my_application.cc @@ -0,0 +1,130 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "tailorhub"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "tailorhub"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/TA_android/linux/runner/my_application.h b/TA_android/linux/runner/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/TA_android/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/TA_android/macos/.gitignore b/TA_android/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/TA_android/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/TA_android/macos/Flutter/Flutter-Debug.xcconfig b/TA_android/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/TA_android/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/TA_android/macos/Flutter/Flutter-Release.xcconfig b/TA_android/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/TA_android/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/TA_android/macos/Flutter/GeneratedPluginRegistrant.swift b/TA_android/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..5642fd6 --- /dev/null +++ b/TA_android/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,26 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import app_settings +import file_selector_macos +import geolocator_apple +import path_provider_foundation +import shared_preferences_foundation +import sqflite +import url_launcher_macos +import webview_flutter_wkwebview + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppSettingsPlugin.register(with: registry.registrar(forPlugin: "AppSettingsPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) +} diff --git a/TA_android/macos/Runner.xcodeproj/project.pbxproj b/TA_android/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e095f76 --- /dev/null +++ b/TA_android/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* tailorhub.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "tailorhub.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* tailorhub.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* tailorhub.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/tailorhub.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/tailorhub"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/tailorhub.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/tailorhub"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/tailorhub.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/tailorhub"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/TA_android/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/TA_android/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/TA_android/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/TA_android/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/TA_android/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..126bb8b --- /dev/null +++ b/TA_android/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TA_android/macos/Runner.xcworkspace/contents.xcworkspacedata b/TA_android/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/TA_android/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/TA_android/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/TA_android/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/TA_android/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/TA_android/macos/Runner/AppDelegate.swift b/TA_android/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..d53ef64 --- /dev/null +++ b/TA_android/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5 GIT binary patch literal 102994 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 0 HcmV?d00001 diff --git a/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0 GIT binary patch literal 5680 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 literal 0 HcmV?d00001 diff --git a/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d GIT binary patch literal 520 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 literal 0 HcmV?d00001 diff --git a/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/TA_android/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46 GIT binary patch literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TA_android/macos/Runner/Configs/AppInfo.xcconfig b/TA_android/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..5aab97e --- /dev/null +++ b/TA_android/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = tailorhub + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.tailorhub + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/TA_android/macos/Runner/Configs/Debug.xcconfig b/TA_android/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/TA_android/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/TA_android/macos/Runner/Configs/Release.xcconfig b/TA_android/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/TA_android/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/TA_android/macos/Runner/Configs/Warnings.xcconfig b/TA_android/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/TA_android/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/TA_android/macos/Runner/DebugProfile.entitlements b/TA_android/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/TA_android/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/TA_android/macos/Runner/Info.plist b/TA_android/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/TA_android/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/TA_android/macos/Runner/MainFlutterWindow.swift b/TA_android/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/TA_android/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/TA_android/macos/Runner/Release.entitlements b/TA_android/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/TA_android/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/TA_android/macos/RunnerTests/RunnerTests.swift b/TA_android/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/TA_android/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/TA_android/pubspec.lock b/TA_android/pubspec.lock new file mode 100644 index 0000000..20fa06e --- /dev/null +++ b/TA_android/pubspec.lock @@ -0,0 +1,1090 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + app_settings: + dependency: "direct main" + description: + name: app_settings + sha256: "3e46c561441e5820d3a25339bf8b51b9e45a5f686873851a20c257a530917795" + url: "https://pub.dev" + source: hosted + version: "6.1.1" + archive: + dependency: transitive + description: + name: archive + sha256: a7f37ff061d7abc2fcf213554b9dcaca713c5853afa5c065c44888bc9ccaf813 + url: "https://pub.dev" + source: hosted + version: "4.0.6" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_cache_manager: + dependency: "direct main" + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b + url: "https://pub.dev" + source: hosted + version: "5.2.1" + flutter_launcher_icons: + dependency: "direct main" + description: + name: flutter_launcher_icons + sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c + url: "https://pub.dev" + source: hosted + version: "0.14.3" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter_map: + dependency: "direct main" + description: + name: flutter_map + sha256: "87cc8349b8fa5dccda5af50018c7374b6645334a0d680931c1fe11bce88fa5bb" + url: "https://pub.dev" + source: hosted + version: "6.2.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" + url: "https://pub.dev" + source: hosted + version: "2.0.22" + flutter_rating_bar: + dependency: "direct main" + description: + name: flutter_rating_bar + sha256: d2af03469eac832c591a1eba47c91ecc871fe5708e69967073c043b2d775ed93 + url: "https://pub.dev" + source: hosted + version: "4.0.1" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b + url: "https://pub.dev" + source: hosted + version: "2.0.17" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a + url: "https://pub.dev" + source: hosted + version: "10.8.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "6cb9fb6e5928b58b9a84bdf85012d757fd07aab8215c5205337021c4999bad27" + url: "https://pub.dev" + source: hosted + version: "11.1.0" + geolocator_android: + dependency: "direct overridden" + description: + name: geolocator_android + sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d + url: "https://pub.dev" + source: hosted + version: "4.6.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: c4ecead17985ede9634f21500072edfcb3dba0ef7b97f8d7bc556d2d722b3ba3 + url: "https://pub.dev" + source: hosted + version: "2.3.9" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "386ce3d9cce47838355000070b1d0b13efb5bc430f8ecda7e9238c8409ace012" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "49d8f846ebeb5e2b6641fe477a7e97e5dd73f03cbfef3fd5c42177b7300fb0ed" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "53da08937d07c24b0d9952eb57a3b474e29aae2abf9dd717f7e1230995f13f0e" + url: "https://pub.dev" + source: hosted + version: "0.2.3" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" + http: + dependency: "direct main" + description: + name: http + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + url: "https://pub.dev" + source: hosted + version: "1.3.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" + url: "https://pub.dev" + source: hosted + version: "4.5.4" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "8c5abf0dcc24fe6e8e0b4a5c0b51a5cf30cefdf6407a3213dae61edc75a70f56" + url: "https://pub.dev" + source: hosted + version: "0.8.12+12" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" + source: hosted + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + latlong2: + dependency: "direct main" + description: + name: latlong2 + sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" + url: "https://pub.dev" + source: hosted + version: "0.9.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + lists: + dependency: transitive + description: + name: lists + sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + logger: + dependency: transitive + description: + name: logger + sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 + url: "https://pub.dev" + source: hosted + version: "2.5.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + mgrs_dart: + dependency: transitive + description: + name: mgrs_dart + sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + mime: + dependency: transitive + description: + name: mime + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + url: "https://pub.dev" + source: hosted + version: "1.0.6" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + url: "https://pub.dev" + source: hosted + version: "2.2.10" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" + url: "https://pub.dev" + source: hosted + version: "11.4.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc + url: "https://pub.dev" + source: hosted + version: "12.1.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + posix: + dependency: transitive + description: + name: posix + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + proj4dart: + dependency: transitive + description: + name: proj4dart + sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e + url: "https://pub.dev" + source: hosted + version: "2.1.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: "489024f942069c2920c844ee18bb3d467c69e48955a4f32d1677f71be103e310" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + simple_gesture_detector: + dependency: transitive + description: + name: simple_gesture_detector + sha256: ba2cd5af24ff20a0b8d609cec3f40e5b0744d2a71804a2616ae086b9c19d19a3 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d + url: "https://pub.dev" + source: hosted + version: "2.3.3+1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + table_calendar: + dependency: "direct main" + description: + name: table_calendar + sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" + source: hosted + version: "0.7.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" + url: "https://pub.dev" + source: hosted + version: "6.3.16" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + uuid: + dependency: transitive + description: + name: uuid + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" + source: hosted + version: "4.5.1" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de" + url: "https://pub.dev" + source: hosted + version: "1.1.18" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" + url: "https://pub.dev" + source: hosted + version: "1.1.16" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" + source: hosted + version: "15.0.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + sha256: caf0f5a1012aa3c2d33c4215adc72dc1194bb59a2d3ed901f457965626805e66 + url: "https://pub.dev" + source: hosted + version: "4.11.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: "6b0eae02b7604954b80ee9a29507ac38f5de74b712faa6fee33abc1cdedc1b21" + url: "https://pub.dev" + source: hosted + version: "4.4.2" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: "18b1640839cf6546784a524c72aded5b6e86b23e7167dc2311cc96f7658b64bd" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: c9f9be526fa0d3347374ceaa05c4b3acb85f4f112abd62f7d74b7d301fa515ff + url: "https://pub.dev" + source: hosted + version: "3.20.0" + wkt_parser: + dependency: transitive + description: + name: wkt_parser + sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.27.0" diff --git a/TA_android/pubspec.yaml b/TA_android/pubspec.yaml new file mode 100644 index 0000000..7d087c9 --- /dev/null +++ b/TA_android/pubspec.yaml @@ -0,0 +1,131 @@ +name: tailorhub +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ">=3.4.1 <4.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + http: ^1.3.0 + shared_preferences: ^2.0.15 + google_fonts: ^6.1.0 + flutter_map: ^6.1.0 + latlong2: ^0.9.0 + geolocator: ^11.0.0 + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.6 + flutter_svg: ^2.0.9 + image_picker: ^1.1.2 + permission_handler: ^11.3.0 + app_settings: ^6.1.1 + intl: ^0.20.2 + table_calendar: ^3.2.0 + cached_network_image: ^3.4.1 + flutter_cache_manager: ^3.4.1 + provider: ^6.1.4 + flutter_rating_bar: ^4.0.1 + flutter_dotenv: ^5.2.1 + flutter_launcher_icons: ^0.14.3 + url_launcher: ^6.3.1 + webview_flutter: ^4.11.0 + font_awesome_flutter: ^10.8.0 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^3.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/images/ + - assets/icons/ + - assets/icons/home/ + - assets/ + - .env + - assets/.env + - assets/images/payment/ + - assets/images/payment_new/ + - assets/images/model_jahit/ + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages + +flutter_launcher_icons: + android: "launcher_icon" + ios: true + image_path: "assets/images/LogoPutih.png" + min_sdk_android: 21 + adaptive_icon_background: "#000000" + adaptive_icon_foreground: "assets/images/LogoPutih.png" + remove_alpha_ios: true + +dependency_overrides: + geolocator_android: 4.6.2 diff --git a/TA_android/temp_gallery_method.txt b/TA_android/temp_gallery_method.txt new file mode 100644 index 0000000..2005f98 --- /dev/null +++ b/TA_android/temp_gallery_method.txt @@ -0,0 +1,47 @@ + } + } + + /// Mengambil galeri penjahit berdasarkan id + static Future> getTailorGallery(int tailorId) async { + try { + print('Fetching tailor gallery for id: $tailorId'); + final token = await getToken(); + + final headers = { + 'Accept': 'application/json', + 'Authorization': token != null ? 'Bearer $token' : '', + }; + + final response = await http.get( + Uri.parse('$baseUrl/tailors/$tailorId/gallery'), + headers: headers, + ); + + print('Tailor gallery response code: ${response.statusCode}'); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + print('Tailor gallery response: ${response.body}'); + + // Parse data gallery ke dalam list GalleryModel + final List galleryItems = []; + + if (data['data'] != null && data['data'] is List) { + for (var item in data['data']) { + galleryItems.add(GalleryModel.fromJson(item)); + } + } + + return { + 'success': true, + 'gallery': galleryItems, + 'message': data['message'] ?? 'Berhasil mendapatkan galeri penjahit', + }; + } else { + return { + 'success': false, + 'gallery': [], + 'message': 'Gagal mendapatkan galeri penjahit', + }; + } + } catch (e) { diff --git a/TA_android/test/widget_test.dart b/TA_android/test/widget_test.dart new file mode 100644 index 0000000..513d8b1 --- /dev/null +++ b/TA_android/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:tailorhub/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp(initialRoute: '/')); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/TA_android/web/favicon.png b/TA_android/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/TA_android/web/icons/Icon-192.png b/TA_android/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/TA_android/web/icons/Icon-512.png b/TA_android/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/TA_android/web/icons/Icon-maskable-192.png b/TA_android/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d GIT binary patch literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! literal 0 HcmV?d00001 diff --git a/TA_android/web/icons/Icon-maskable-512.png b/TA_android/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e GIT binary patch literal 20998 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 MPgg&ebxsLQ025IeI{*Lx literal 0 HcmV?d00001 diff --git a/TA_android/web/index.html b/TA_android/web/index.html new file mode 100644 index 0000000..fab690f --- /dev/null +++ b/TA_android/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + tailorhub + + + + + + diff --git a/TA_android/web/manifest.json b/TA_android/web/manifest.json new file mode 100644 index 0000000..06ed387 --- /dev/null +++ b/TA_android/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "tailorhub", + "short_name": "tailorhub", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/TA_android/windows/.gitignore b/TA_android/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/TA_android/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/TA_android/windows/CMakeLists.txt b/TA_android/windows/CMakeLists.txt new file mode 100644 index 0000000..d77b111 --- /dev/null +++ b/TA_android/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(tailorhub LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "tailorhub") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/TA_android/windows/flutter/CMakeLists.txt b/TA_android/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/TA_android/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/TA_android/windows/flutter/generated_plugin_registrant.cc b/TA_android/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..b2cbd25 --- /dev/null +++ b/TA_android/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,23 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/TA_android/windows/flutter/generated_plugin_registrant.h b/TA_android/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/TA_android/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/TA_android/windows/flutter/generated_plugins.cmake b/TA_android/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..92c9a0d --- /dev/null +++ b/TA_android/windows/flutter/generated_plugins.cmake @@ -0,0 +1,27 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows + geolocator_windows + permission_handler_windows + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/TA_android/windows/runner/CMakeLists.txt b/TA_android/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/TA_android/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/TA_android/windows/runner/Runner.rc b/TA_android/windows/runner/Runner.rc new file mode 100644 index 0000000..b3021a3 --- /dev/null +++ b/TA_android/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "tailorhub" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "tailorhub" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "tailorhub.exe" "\0" + VALUE "ProductName", "tailorhub" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/TA_android/windows/runner/flutter_window.cpp b/TA_android/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/TA_android/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/TA_android/windows/runner/flutter_window.h b/TA_android/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/TA_android/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/TA_android/windows/runner/main.cpp b/TA_android/windows/runner/main.cpp new file mode 100644 index 0000000..b51a5c4 --- /dev/null +++ b/TA_android/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"tailorhub", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/TA_android/windows/runner/resource.h b/TA_android/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/TA_android/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/TA_android/windows/runner/resources/app_icon.ico b/TA_android/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6 GIT binary patch literal 33772 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 literal 0 HcmV?d00001 diff --git a/TA_android/windows/runner/runner.exe.manifest b/TA_android/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..153653e --- /dev/null +++ b/TA_android/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/TA_android/windows/runner/utils.cpp b/TA_android/windows/runner/utils.cpp new file mode 100644 index 0000000..3a0b465 --- /dev/null +++ b/TA_android/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/TA_android/windows/runner/utils.h b/TA_android/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/TA_android/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/TA_android/windows/runner/win32_window.cpp b/TA_android/windows/runner/win32_window.cpp new file mode 100644 index 0000000..60608d0 --- /dev/null +++ b/TA_android/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/TA_android/windows/runner/win32_window.h b/TA_android/windows/runner/win32_window.h new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/TA_android/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/TA_website/.editorconfig b/TA_website/.editorconfig new file mode 100644 index 0000000..8f0de65 --- /dev/null +++ b/TA_website/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[docker-compose.yml] +indent_size = 4 diff --git a/TA_website/.env.example b/TA_website/.env.example new file mode 100644 index 0000000..35db1dd --- /dev/null +++ b/TA_website/.env.example @@ -0,0 +1,65 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_STORE=database + +PHP_CLI_SERVER_WORKERS=4 + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=sqlite +# DB_HOST=127.0.0.1 +# DB_PORT=3306 +# DB_DATABASE=laravel +# DB_USERNAME=root +# DB_PASSWORD= + +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +# CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +VITE_APP_NAME="${APP_NAME}" diff --git a/TA_website/.gitattributes b/TA_website/.gitattributes new file mode 100644 index 0000000..fcb21d3 --- /dev/null +++ b/TA_website/.gitattributes @@ -0,0 +1,11 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/TA_website/.gitignore b/TA_website/.gitignore new file mode 100644 index 0000000..c7cf1fa --- /dev/null +++ b/TA_website/.gitignore @@ -0,0 +1,23 @@ +/.phpunit.cache +/node_modules +/public/build +/public/hot +/public/storage +/storage/*.key +/storage/pail +/vendor +.env +.env.backup +.env.production +.phpactor.json +.phpunit.result.cache +Homestead.json +Homestead.yaml +npm-debug.log +yarn-error.log +/auth.json +/.fleet +/.idea +/.nova +/.vscode +/.zed diff --git a/TA_website/README.md b/TA_website/README.md new file mode 100644 index 0000000..1a4c26b --- /dev/null +++ b/TA_website/README.md @@ -0,0 +1,66 @@ + + +

+Build Status +Total Downloads +Latest Stable Version +License +

+ +## About Laravel + +Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: + +- [Simple, fast routing engine](https://laravel.com/docs/routing). +- [Powerful dependency injection container](https://laravel.com/docs/container). +- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. +- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). +- Database agnostic [schema migrations](https://laravel.com/docs/migrations). +- [Robust background job processing](https://laravel.com/docs/queues). +- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). + +Laravel is accessible, powerful, and provides tools required for large, robust applications. + +## Learning Laravel + +Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. + +You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch. + +If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. + +## Laravel Sponsors + +We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com). + +### Premium Partners + +- **[Vehikl](https://vehikl.com/)** +- **[Tighten Co.](https://tighten.co)** +- **[WebReinvent](https://webreinvent.com/)** +- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** +- **[64 Robots](https://64robots.com)** +- **[Curotec](https://www.curotec.com/services/technologies/laravel/)** +- **[Cyber-Duck](https://cyber-duck.co.uk)** +- **[DevSquad](https://devsquad.com/hire-laravel-developers)** +- **[Jump24](https://jump24.co.uk)** +- **[Redberry](https://redberry.international/laravel/)** +- **[Active Logic](https://activelogic.com)** +- **[byte5](https://byte5.de)** +- **[OP.GG](https://op.gg)** + +## Contributing + +Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). + +## Code of Conduct + +In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). + +## Security Vulnerabilities + +If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. + +## License + +The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). diff --git a/TA_website/_ide_helper.php b/TA_website/_ide_helper.php new file mode 100644 index 0000000..7a6f5ef --- /dev/null +++ b/TA_website/_ide_helper.php @@ -0,0 +1,27492 @@ + + * @see https://github.com/barryvdh/laravel-ide-helper + */ +namespace Illuminate\Support\Facades { + /** + * + * + * @see \Illuminate\Foundation\Application + */ + class App { + /** + * Begin configuring a new Laravel application instance. + * + * @param string|null $basePath + * @return \Illuminate\Foundation\Configuration\ApplicationBuilder + * @static + */ + public static function configure($basePath = null) + { + return \Illuminate\Foundation\Application::configure($basePath); + } + + /** + * Infer the application's base directory from the environment. + * + * @return string + * @static + */ + public static function inferBasePath() + { + return \Illuminate\Foundation\Application::inferBasePath(); + } + + /** + * Get the version number of the application. + * + * @return string + * @static + */ + public static function version() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->version(); + } + + /** + * Run the given array of bootstrap classes. + * + * @param string[] $bootstrappers + * @return void + * @static + */ + public static function bootstrapWith($bootstrappers) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bootstrapWith($bootstrappers); + } + + /** + * Register a callback to run after loading the environment. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function afterLoadingEnvironment($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterLoadingEnvironment($callback); + } + + /** + * Register a callback to run before a bootstrapper. + * + * @param string $bootstrapper + * @param \Closure $callback + * @return void + * @static + */ + public static function beforeBootstrapping($bootstrapper, $callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->beforeBootstrapping($bootstrapper, $callback); + } + + /** + * Register a callback to run after a bootstrapper. + * + * @param string $bootstrapper + * @param \Closure $callback + * @return void + * @static + */ + public static function afterBootstrapping($bootstrapper, $callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterBootstrapping($bootstrapper, $callback); + } + + /** + * Determine if the application has been bootstrapped before. + * + * @return bool + * @static + */ + public static function hasBeenBootstrapped() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->hasBeenBootstrapped(); + } + + /** + * Set the base path for the application. + * + * @param string $basePath + * @return \Illuminate\Foundation\Application + * @static + */ + public static function setBasePath($basePath) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->setBasePath($basePath); + } + + /** + * Get the path to the application "app" directory. + * + * @param string $path + * @return string + * @static + */ + public static function path($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->path($path); + } + + /** + * Set the application directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useAppPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useAppPath($path); + } + + /** + * Get the base path of the Laravel installation. + * + * @param string $path + * @return string + * @static + */ + public static function basePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->basePath($path); + } + + /** + * Get the path to the bootstrap directory. + * + * @param string $path + * @return string + * @static + */ + public static function bootstrapPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->bootstrapPath($path); + } + + /** + * Get the path to the service provider list in the bootstrap directory. + * + * @return string + * @static + */ + public static function getBootstrapProvidersPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getBootstrapProvidersPath(); + } + + /** + * Set the bootstrap file directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useBootstrapPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useBootstrapPath($path); + } + + /** + * Get the path to the application configuration files. + * + * @param string $path + * @return string + * @static + */ + public static function configPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->configPath($path); + } + + /** + * Set the configuration directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useConfigPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useConfigPath($path); + } + + /** + * Get the path to the database directory. + * + * @param string $path + * @return string + * @static + */ + public static function databasePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->databasePath($path); + } + + /** + * Set the database directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useDatabasePath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useDatabasePath($path); + } + + /** + * Get the path to the language files. + * + * @param string $path + * @return string + * @static + */ + public static function langPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->langPath($path); + } + + /** + * Set the language file directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useLangPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useLangPath($path); + } + + /** + * Get the path to the public / web directory. + * + * @param string $path + * @return string + * @static + */ + public static function publicPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->publicPath($path); + } + + /** + * Set the public / web directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function usePublicPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->usePublicPath($path); + } + + /** + * Get the path to the storage directory. + * + * @param string $path + * @return string + * @static + */ + public static function storagePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->storagePath($path); + } + + /** + * Set the storage directory. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useStoragePath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useStoragePath($path); + } + + /** + * Get the path to the resources directory. + * + * @param string $path + * @return string + * @static + */ + public static function resourcePath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resourcePath($path); + } + + /** + * Get the path to the views directory. + * + * This method returns the first configured path in the array of view paths. + * + * @param string $path + * @return string + * @static + */ + public static function viewPath($path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->viewPath($path); + } + + /** + * Join the given paths together. + * + * @param string $basePath + * @param string $path + * @return string + * @static + */ + public static function joinPaths($basePath, $path = '') + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->joinPaths($basePath, $path); + } + + /** + * Get the path to the environment file directory. + * + * @return string + * @static + */ + public static function environmentPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environmentPath(); + } + + /** + * Set the directory for the environment file. + * + * @param string $path + * @return \Illuminate\Foundation\Application + * @static + */ + public static function useEnvironmentPath($path) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->useEnvironmentPath($path); + } + + /** + * Set the environment file to be loaded during bootstrapping. + * + * @param string $file + * @return \Illuminate\Foundation\Application + * @static + */ + public static function loadEnvironmentFrom($file) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->loadEnvironmentFrom($file); + } + + /** + * Get the environment file the application is using. + * + * @return string + * @static + */ + public static function environmentFile() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environmentFile(); + } + + /** + * Get the fully qualified path to the environment file. + * + * @return string + * @static + */ + public static function environmentFilePath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environmentFilePath(); + } + + /** + * Get or check the current application environment. + * + * @param string|array $environments + * @return string|bool + * @static + */ + public static function environment(...$environments) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->environment(...$environments); + } + + /** + * Determine if the application is in the local environment. + * + * @return bool + * @static + */ + public static function isLocal() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isLocal(); + } + + /** + * Determine if the application is in the production environment. + * + * @return bool + * @static + */ + public static function isProduction() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isProduction(); + } + + /** + * Detect the application's current environment. + * + * @param \Closure $callback + * @return string + * @static + */ + public static function detectEnvironment($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->detectEnvironment($callback); + } + + /** + * Determine if the application is running in the console. + * + * @return bool + * @static + */ + public static function runningInConsole() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->runningInConsole(); + } + + /** + * Determine if the application is running any of the given console commands. + * + * @param string|array $commands + * @return bool + * @static + */ + public static function runningConsoleCommand(...$commands) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->runningConsoleCommand(...$commands); + } + + /** + * Determine if the application is running unit tests. + * + * @return bool + * @static + */ + public static function runningUnitTests() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->runningUnitTests(); + } + + /** + * Determine if the application is running with debug mode enabled. + * + * @return bool + * @static + */ + public static function hasDebugModeEnabled() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->hasDebugModeEnabled(); + } + + /** + * Register a new registered listener. + * + * @param callable $callback + * @return void + * @static + */ + public static function registered($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registered($callback); + } + + /** + * Register all of the configured providers. + * + * @return void + * @static + */ + public static function registerConfiguredProviders() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registerConfiguredProviders(); + } + + /** + * Register a service provider with the application. + * + * @param \Illuminate\Support\ServiceProvider|string $provider + * @param bool $force + * @return \Illuminate\Support\ServiceProvider + * @static + */ + public static function register($provider, $force = false) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->register($provider, $force); + } + + /** + * Get the registered service provider instance if it exists. + * + * @param \Illuminate\Support\ServiceProvider|string $provider + * @return \Illuminate\Support\ServiceProvider|null + * @static + */ + public static function getProvider($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getProvider($provider); + } + + /** + * Get the registered service provider instances if any exist. + * + * @param \Illuminate\Support\ServiceProvider|string $provider + * @return array + * @static + */ + public static function getProviders($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getProviders($provider); + } + + /** + * Resolve a service provider instance from the class name. + * + * @param string $provider + * @return \Illuminate\Support\ServiceProvider + * @static + */ + public static function resolveProvider($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resolveProvider($provider); + } + + /** + * Load and boot all of the remaining deferred providers. + * + * @return void + * @static + */ + public static function loadDeferredProviders() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->loadDeferredProviders(); + } + + /** + * Load the provider for a deferred service. + * + * @param string $service + * @return void + * @static + */ + public static function loadDeferredProvider($service) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->loadDeferredProvider($service); + } + + /** + * Register a deferred provider and service. + * + * @param string $provider + * @param string|null $service + * @return void + * @static + */ + public static function registerDeferredProvider($provider, $service = null) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registerDeferredProvider($provider, $service); + } + + /** + * Resolve the given type from the container. + * + * @template TClass of object + * @param string|class-string $abstract + * @param array $parameters + * @return ($abstract is class-string ? TClass : mixed) + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @static + */ + public static function make($abstract, $parameters = []) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->make($abstract, $parameters); + } + + /** + * Determine if the given abstract type has been bound. + * + * @param string $abstract + * @return bool + * @static + */ + public static function bound($abstract) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->bound($abstract); + } + + /** + * Determine if the application has booted. + * + * @return bool + * @static + */ + public static function isBooted() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isBooted(); + } + + /** + * Boot the application's service providers. + * + * @return void + * @static + */ + public static function boot() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->boot(); + } + + /** + * Register a new boot listener. + * + * @param callable $callback + * @return void + * @static + */ + public static function booting($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->booting($callback); + } + + /** + * Register a new "booted" listener. + * + * @param callable $callback + * @return void + * @static + */ + public static function booted($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->booted($callback); + } + + /** + * {@inheritdoc} + * + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function handle($request, $type = 1, $catch = true) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->handle($request, $type, $catch); + } + + /** + * Handle the incoming HTTP request and send the response to the browser. + * + * @param \Illuminate\Http\Request $request + * @return void + * @static + */ + public static function handleRequest($request) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->handleRequest($request); + } + + /** + * Handle the incoming Artisan command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @return int + * @static + */ + public static function handleCommand($input) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->handleCommand($input); + } + + /** + * Determine if the framework's base configuration should be merged. + * + * @return bool + * @static + */ + public static function shouldMergeFrameworkConfiguration() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->shouldMergeFrameworkConfiguration(); + } + + /** + * Indicate that the framework's base configuration should not be merged. + * + * @return \Illuminate\Foundation\Application + * @static + */ + public static function dontMergeFrameworkConfiguration() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->dontMergeFrameworkConfiguration(); + } + + /** + * Determine if middleware has been disabled for the application. + * + * @return bool + * @static + */ + public static function shouldSkipMiddleware() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->shouldSkipMiddleware(); + } + + /** + * Get the path to the cached services.php file. + * + * @return string + * @static + */ + public static function getCachedServicesPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedServicesPath(); + } + + /** + * Get the path to the cached packages.php file. + * + * @return string + * @static + */ + public static function getCachedPackagesPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedPackagesPath(); + } + + /** + * Determine if the application configuration is cached. + * + * @return bool + * @static + */ + public static function configurationIsCached() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->configurationIsCached(); + } + + /** + * Get the path to the configuration cache file. + * + * @return string + * @static + */ + public static function getCachedConfigPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedConfigPath(); + } + + /** + * Determine if the application routes are cached. + * + * @return bool + * @static + */ + public static function routesAreCached() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->routesAreCached(); + } + + /** + * Get the path to the routes cache file. + * + * @return string + * @static + */ + public static function getCachedRoutesPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedRoutesPath(); + } + + /** + * Determine if the application events are cached. + * + * @return bool + * @static + */ + public static function eventsAreCached() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->eventsAreCached(); + } + + /** + * Get the path to the events cache file. + * + * @return string + * @static + */ + public static function getCachedEventsPath() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getCachedEventsPath(); + } + + /** + * Add new prefix to list of absolute path prefixes. + * + * @param string $prefix + * @return \Illuminate\Foundation\Application + * @static + */ + public static function addAbsoluteCachePathPrefix($prefix) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->addAbsoluteCachePathPrefix($prefix); + } + + /** + * Get an instance of the maintenance mode manager implementation. + * + * @return \Illuminate\Contracts\Foundation\MaintenanceMode + * @static + */ + public static function maintenanceMode() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->maintenanceMode(); + } + + /** + * Determine if the application is currently down for maintenance. + * + * @return bool + * @static + */ + public static function isDownForMaintenance() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isDownForMaintenance(); + } + + /** + * Throw an HttpException with the given data. + * + * @param int $code + * @param string $message + * @param array $headers + * @return never + * @throws \Symfony\Component\HttpKernel\Exception\HttpException + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + * @static + */ + public static function abort($code, $message = '', $headers = []) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->abort($code, $message, $headers); + } + + /** + * Register a terminating callback with the application. + * + * @param callable|string $callback + * @return \Illuminate\Foundation\Application + * @static + */ + public static function terminating($callback) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->terminating($callback); + } + + /** + * Terminate the application. + * + * @return void + * @static + */ + public static function terminate() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->terminate(); + } + + /** + * Get the service providers that have been loaded. + * + * @return array + * @static + */ + public static function getLoadedProviders() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getLoadedProviders(); + } + + /** + * Determine if the given service provider is loaded. + * + * @param string $provider + * @return bool + * @static + */ + public static function providerIsLoaded($provider) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->providerIsLoaded($provider); + } + + /** + * Get the application's deferred services. + * + * @return array + * @static + */ + public static function getDeferredServices() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getDeferredServices(); + } + + /** + * Set the application's deferred services. + * + * @param array $services + * @return void + * @static + */ + public static function setDeferredServices($services) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->setDeferredServices($services); + } + + /** + * Determine if the given service is a deferred service. + * + * @param string $service + * @return bool + * @static + */ + public static function isDeferredService($service) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isDeferredService($service); + } + + /** + * Add an array of services to the application's deferred services. + * + * @param array $services + * @return void + * @static + */ + public static function addDeferredServices($services) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->addDeferredServices($services); + } + + /** + * Remove an array of services from the application's deferred services. + * + * @param array $services + * @return void + * @static + */ + public static function removeDeferredServices($services) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->removeDeferredServices($services); + } + + /** + * Configure the real-time facade namespace. + * + * @param string $namespace + * @return void + * @static + */ + public static function provideFacades($namespace) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->provideFacades($namespace); + } + + /** + * Get the current application locale. + * + * @return string + * @static + */ + public static function getLocale() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getLocale(); + } + + /** + * Get the current application locale. + * + * @return string + * @static + */ + public static function currentLocale() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->currentLocale(); + } + + /** + * Get the current application fallback locale. + * + * @return string + * @static + */ + public static function getFallbackLocale() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getFallbackLocale(); + } + + /** + * Set the current application locale. + * + * @param string $locale + * @return void + * @static + */ + public static function setLocale($locale) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->setLocale($locale); + } + + /** + * Set the current application fallback locale. + * + * @param string $fallbackLocale + * @return void + * @static + */ + public static function setFallbackLocale($fallbackLocale) + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->setFallbackLocale($fallbackLocale); + } + + /** + * Determine if the application locale is the given locale. + * + * @param string $locale + * @return bool + * @static + */ + public static function isLocale($locale) + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isLocale($locale); + } + + /** + * Register the core class aliases in the container. + * + * @return void + * @static + */ + public static function registerCoreContainerAliases() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->registerCoreContainerAliases(); + } + + /** + * Flush the container of all bindings and resolved instances. + * + * @return void + * @static + */ + public static function flush() + { + /** @var \Illuminate\Foundation\Application $instance */ + $instance->flush(); + } + + /** + * Get the application namespace. + * + * @return string + * @throws \RuntimeException + * @static + */ + public static function getNamespace() + { + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getNamespace(); + } + + /** + * Define a contextual binding. + * + * @param array|string $concrete + * @return \Illuminate\Contracts\Container\ContextualBindingBuilder + * @static + */ + public static function when($concrete) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->when($concrete); + } + + /** + * Define a contextual binding based on an attribute. + * + * @param string $attribute + * @param \Closure $handler + * @return void + * @static + */ + public static function whenHasAttribute($attribute, $handler) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->whenHasAttribute($attribute, $handler); + } + + /** + * Returns true if the container can return an entry for the given identifier. + * + * Returns false otherwise. + * + * `has($id)` returning true does not mean that `get($id)` will not throw an exception. + * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`. + * + * @return bool + * @param string $id Identifier of the entry to look for. + * @return bool + * @static + */ + public static function has($id) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->has($id); + } + + /** + * Determine if the given abstract type has been resolved. + * + * @param string $abstract + * @return bool + * @static + */ + public static function resolved($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resolved($abstract); + } + + /** + * Determine if a given type is shared. + * + * @param string $abstract + * @return bool + * @static + */ + public static function isShared($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isShared($abstract); + } + + /** + * Determine if a given string is an alias. + * + * @param string $name + * @return bool + * @static + */ + public static function isAlias($name) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->isAlias($name); + } + + /** + * Register a binding with the container. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + * @throws \TypeError + * @throws ReflectionException + * @static + */ + public static function bind($abstract, $concrete = null, $shared = false) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bind($abstract, $concrete, $shared); + } + + /** + * Determine if the container has a method binding. + * + * @param string $method + * @return bool + * @static + */ + public static function hasMethodBinding($method) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->hasMethodBinding($method); + } + + /** + * Bind a callback to resolve with Container::call. + * + * @param array|string $method + * @param \Closure $callback + * @return void + * @static + */ + public static function bindMethod($method, $callback) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bindMethod($method, $callback); + } + + /** + * Get the method binding for the given method. + * + * @param string $method + * @param mixed $instance + * @return mixed + * @static + */ + public static function callMethodBinding($method, $instance) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->callMethodBinding($method, $instance); + } + + /** + * Add a contextual binding to the container. + * + * @param string $concrete + * @param \Closure|string $abstract + * @param \Closure|string $implementation + * @return void + * @static + */ + public static function addContextualBinding($concrete, $abstract, $implementation) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->addContextualBinding($concrete, $abstract, $implementation); + } + + /** + * Register a binding if it hasn't already been registered. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + * @static + */ + public static function bindIf($abstract, $concrete = null, $shared = false) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->bindIf($abstract, $concrete, $shared); + } + + /** + * Register a shared binding in the container. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function singleton($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->singleton($abstract, $concrete); + } + + /** + * Register a shared binding if it hasn't already been registered. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function singletonIf($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->singletonIf($abstract, $concrete); + } + + /** + * Register a scoped binding in the container. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function scoped($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->scoped($abstract, $concrete); + } + + /** + * Register a scoped binding if it hasn't already been registered. + * + * @param \Closure|string $abstract + * @param \Closure|string|null $concrete + * @return void + * @static + */ + public static function scopedIf($abstract, $concrete = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->scopedIf($abstract, $concrete); + } + + /** + * "Extend" an abstract type in the container. + * + * @param string $abstract + * @param \Closure $closure + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function extend($abstract, $closure) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->extend($abstract, $closure); + } + + /** + * Register an existing instance as shared in the container. + * + * @template TInstance of mixed + * @param string $abstract + * @param TInstance $instance + * @return TInstance + * @static + */ + public static function instance($abstract, $instance) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->instance($abstract, $instance); + } + + /** + * Assign a set of tags to a given binding. + * + * @param array|string $abstracts + * @param array|mixed $tags + * @return void + * @static + */ + public static function tag($abstracts, $tags) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->tag($abstracts, $tags); + } + + /** + * Resolve all of the bindings for a given tag. + * + * @param string $tag + * @return iterable + * @static + */ + public static function tagged($tag) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->tagged($tag); + } + + /** + * Alias a type to a different name. + * + * @param string $abstract + * @param string $alias + * @return void + * @throws \LogicException + * @static + */ + public static function alias($abstract, $alias) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->alias($abstract, $alias); + } + + /** + * Bind a new callback to an abstract's rebind event. + * + * @param string $abstract + * @param \Closure $callback + * @return mixed + * @static + */ + public static function rebinding($abstract, $callback) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->rebinding($abstract, $callback); + } + + /** + * Refresh an instance on the given target and method. + * + * @param string $abstract + * @param mixed $target + * @param string $method + * @return mixed + * @static + */ + public static function refresh($abstract, $target, $method) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->refresh($abstract, $target, $method); + } + + /** + * Wrap the given closure such that its dependencies will be injected when executed. + * + * @param \Closure $callback + * @param array $parameters + * @return \Closure + * @static + */ + public static function wrap($callback, $parameters = []) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->wrap($callback, $parameters); + } + + /** + * Call the given Closure / class@method and inject its dependencies. + * + * @param callable|string $callback + * @param array $parameters + * @param string|null $defaultMethod + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function call($callback, $parameters = [], $defaultMethod = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->call($callback, $parameters, $defaultMethod); + } + + /** + * Get a closure to resolve the given type from the container. + * + * @template TClass of object + * @param string|class-string $abstract + * @return ($abstract is class-string ? \Closure(): TClass : \Closure(): mixed) + * @static + */ + public static function factory($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->factory($abstract); + } + + /** + * An alias function name for make(). + * + * @template TClass of object + * @param string|class-string|callable $abstract + * @param array $parameters + * @return ($abstract is class-string ? TClass : mixed) + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @static + */ + public static function makeWith($abstract, $parameters = []) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->makeWith($abstract, $parameters); + } + + /** + * {@inheritdoc} + * + * @template TClass of object + * @param string|class-string $id + * @return ($id is class-string ? TClass : mixed) + * @static + */ + public static function get($id) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->get($id); + } + + /** + * Instantiate a concrete instance of the given type. + * + * @template TClass of object + * @param \Closure(static, array): TClass|class-string $concrete + * @return TClass + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @throws \Illuminate\Contracts\Container\CircularDependencyException + * @static + */ + public static function build($concrete) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->build($concrete); + } + + /** + * Resolve a dependency based on an attribute. + * + * @param \ReflectionAttribute $attribute + * @return mixed + * @static + */ + public static function resolveFromAttribute($attribute) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->resolveFromAttribute($attribute); + } + + /** + * Register a new before resolving callback for all types. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + * @static + */ + public static function beforeResolving($abstract, $callback = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->beforeResolving($abstract, $callback); + } + + /** + * Register a new resolving callback. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + * @static + */ + public static function resolving($abstract, $callback = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->resolving($abstract, $callback); + } + + /** + * Register a new after resolving callback for all types. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + * @static + */ + public static function afterResolving($abstract, $callback = null) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterResolving($abstract, $callback); + } + + /** + * Register a new after resolving attribute callback for all types. + * + * @param string $attribute + * @param \Closure $callback + * @return void + * @static + */ + public static function afterResolvingAttribute($attribute, $callback) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->afterResolvingAttribute($attribute, $callback); + } + + /** + * Fire all of the after resolving attribute callbacks. + * + * @param \ReflectionAttribute[] $attributes + * @param mixed $object + * @return void + * @static + */ + public static function fireAfterResolvingAttributeCallbacks($attributes, $object) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->fireAfterResolvingAttributeCallbacks($attributes, $object); + } + + /** + * Get the container's bindings. + * + * @return array + * @static + */ + public static function getBindings() + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getBindings(); + } + + /** + * Get the alias for an abstract if available. + * + * @param string $abstract + * @return string + * @static + */ + public static function getAlias($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->getAlias($abstract); + } + + /** + * Remove all of the extender callbacks for a given type. + * + * @param string $abstract + * @return void + * @static + */ + public static function forgetExtenders($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetExtenders($abstract); + } + + /** + * Remove a resolved instance from the instance cache. + * + * @param string $abstract + * @return void + * @static + */ + public static function forgetInstance($abstract) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetInstance($abstract); + } + + /** + * Clear all of the instances from the container. + * + * @return void + * @static + */ + public static function forgetInstances() + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetInstances(); + } + + /** + * Clear all of the scoped instances from the container. + * + * @return void + * @static + */ + public static function forgetScopedInstances() + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->forgetScopedInstances(); + } + + /** + * Get the globally available instance of the container. + * + * @return static + * @static + */ + public static function getInstance() + { + //Method inherited from \Illuminate\Container\Container + return \Illuminate\Foundation\Application::getInstance(); + } + + /** + * Set the shared instance of the container. + * + * @param \Illuminate\Contracts\Container\Container|null $container + * @return \Illuminate\Contracts\Container\Container|static + * @static + */ + public static function setInstance($container = null) + { + //Method inherited from \Illuminate\Container\Container + return \Illuminate\Foundation\Application::setInstance($container); + } + + /** + * Determine if a given offset exists. + * + * @param string $key + * @return bool + * @static + */ + public static function offsetExists($key) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->offsetExists($key); + } + + /** + * Get the value at a given offset. + * + * @param string $key + * @return mixed + * @static + */ + public static function offsetGet($key) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + return $instance->offsetGet($key); + } + + /** + * Set the value at a given offset. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($key, $value) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->offsetSet($key, $value); + } + + /** + * Unset the value at a given offset. + * + * @param string $key + * @return void + * @static + */ + public static function offsetUnset($key) + { + //Method inherited from \Illuminate\Container\Container + /** @var \Illuminate\Foundation\Application $instance */ + $instance->offsetUnset($key); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Foundation\Application::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Foundation\Application::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Foundation\Application::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Foundation\Application::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Foundation\Console\Kernel + */ + class Artisan { + /** + * Re-route the Symfony command events to their Laravel counterparts. + * + * @internal + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function rerouteSymfonyCommandEvents() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->rerouteSymfonyCommandEvents(); + } + + /** + * Run the console application. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface|null $output + * @return int + * @static + */ + public static function handle($input, $output = null) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->handle($input, $output); + } + + /** + * Terminate the application. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param int $status + * @return void + * @static + */ + public static function terminate($input, $status) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->terminate($input, $status); + } + + /** + * Register a callback to be invoked when the command lifecycle duration exceeds a given amount of time. + * + * @param \DateTimeInterface|\Carbon\CarbonInterval|float|int $threshold + * @param callable $handler + * @return void + * @static + */ + public static function whenCommandLifecycleIsLongerThan($threshold, $handler) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->whenCommandLifecycleIsLongerThan($threshold, $handler); + } + + /** + * When the command being handled started. + * + * @return \Illuminate\Support\Carbon|null + * @static + */ + public static function commandStartedAt() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->commandStartedAt(); + } + + /** + * Resolve a console schedule instance. + * + * @return \Illuminate\Console\Scheduling\Schedule + * @static + */ + public static function resolveConsoleSchedule() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->resolveConsoleSchedule(); + } + + /** + * Register a Closure based command with the application. + * + * @param string $signature + * @param \Closure $callback + * @return \Illuminate\Foundation\Console\ClosureCommand + * @static + */ + public static function command($signature, $callback) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->command($signature, $callback); + } + + /** + * Register the given command with the console application. + * + * @param \Symfony\Component\Console\Command\Command $command + * @return void + * @static + */ + public static function registerCommand($command) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->registerCommand($command); + } + + /** + * Run an Artisan console command by name. + * + * @param string $command + * @param array $parameters + * @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer + * @return int + * @throws \Symfony\Component\Console\Exception\CommandNotFoundException + * @static + */ + public static function call($command, $parameters = [], $outputBuffer = null) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->call($command, $parameters, $outputBuffer); + } + + /** + * Queue the given console command. + * + * @param string $command + * @param array $parameters + * @return \Illuminate\Foundation\Bus\PendingDispatch + * @static + */ + public static function queue($command, $parameters = []) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->queue($command, $parameters); + } + + /** + * Get all of the commands registered with the console. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->all(); + } + + /** + * Get the output for the last run command. + * + * @return string + * @static + */ + public static function output() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->output(); + } + + /** + * Bootstrap the application for artisan commands. + * + * @return void + * @static + */ + public static function bootstrap() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->bootstrap(); + } + + /** + * Bootstrap the application without booting service providers. + * + * @return void + * @static + */ + public static function bootstrapWithoutBootingProviders() + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->bootstrapWithoutBootingProviders(); + } + + /** + * Set the Artisan application instance. + * + * @param \Illuminate\Console\Application|null $artisan + * @return void + * @static + */ + public static function setArtisan($artisan) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + $instance->setArtisan($artisan); + } + + /** + * Set the Artisan commands provided by the application. + * + * @param array $commands + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function addCommands($commands) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->addCommands($commands); + } + + /** + * Set the paths that should have their Artisan commands automatically discovered. + * + * @param array $paths + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function addCommandPaths($paths) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->addCommandPaths($paths); + } + + /** + * Set the paths that should have their Artisan "routes" automatically discovered. + * + * @param array $paths + * @return \Illuminate\Foundation\Console\Kernel + * @static + */ + public static function addCommandRoutePaths($paths) + { + /** @var \Illuminate\Foundation\Console\Kernel $instance */ + return $instance->addCommandRoutePaths($paths); + } + + } + /** + * + * + * @see \Illuminate\Auth\AuthManager + * @see \Illuminate\Auth\SessionGuard + */ + class Auth { + /** + * Attempt to get the guard from the local cache. + * + * @param string|null $name + * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard + * @static + */ + public static function guard($name = null) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->guard($name); + } + + /** + * Create a session based authentication guard. + * + * @param string $name + * @param array $config + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function createSessionDriver($name, $config) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->createSessionDriver($name, $config); + } + + /** + * Create a token based authentication guard. + * + * @param string $name + * @param array $config + * @return \Illuminate\Auth\TokenGuard + * @static + */ + public static function createTokenDriver($name, $config) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->createTokenDriver($name, $config); + } + + /** + * Get the default authentication driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default guard driver the factory should serve. + * + * @param string $name + * @return void + * @static + */ + public static function shouldUse($name) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + $instance->shouldUse($name); + } + + /** + * Set the default authentication driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Register a new callback based request guard. + * + * @param string $driver + * @param callable $callback + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function viaRequest($driver, $callback) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->viaRequest($driver, $callback); + } + + /** + * Get the user resolver callback. + * + * @return \Closure + * @static + */ + public static function userResolver() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->userResolver(); + } + + /** + * Set the callback to be used to resolve users. + * + * @param \Closure $userResolver + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function resolveUsersUsing($userResolver) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->resolveUsersUsing($userResolver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Register a custom provider creator Closure. + * + * @param string $name + * @param \Closure $callback + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function provider($name, $callback) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->provider($name, $callback); + } + + /** + * Determines if any guards have already been resolved. + * + * @return bool + * @static + */ + public static function hasResolvedGuards() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->hasResolvedGuards(); + } + + /** + * Forget all of the resolved guard instances. + * + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function forgetGuards() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->forgetGuards(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Auth\AuthManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->setApplication($app); + } + + /** + * Create the user provider implementation for the driver. + * + * @param string|null $provider + * @return \Illuminate\Contracts\Auth\UserProvider|null + * @throws \InvalidArgumentException + * @static + */ + public static function createUserProvider($provider = null) + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->createUserProvider($provider); + } + + /** + * Get the default user provider name. + * + * @return string + * @static + */ + public static function getDefaultUserProvider() + { + /** @var \Illuminate\Auth\AuthManager $instance */ + return $instance->getDefaultUserProvider(); + } + + /** + * Get the currently authenticated user. + * + * @return \App\Models\User|null + * @static + */ + public static function user() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->user(); + } + + /** + * Get the ID for the currently authenticated user. + * + * @return int|string|null + * @static + */ + public static function id() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->id(); + } + + /** + * Log a user into the application without sessions or cookies. + * + * @param array $credentials + * @return bool + * @static + */ + public static function once($credentials = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->once($credentials); + } + + /** + * Log the given user ID into the application without sessions or cookies. + * + * @param mixed $id + * @return \App\Models\User|false + * @static + */ + public static function onceUsingId($id) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->onceUsingId($id); + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + * @static + */ + public static function validate($credentials = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->validate($credentials); + } + + /** + * Attempt to authenticate using HTTP Basic Auth. + * + * @param string $field + * @param array $extraConditions + * @return \Symfony\Component\HttpFoundation\Response|null + * @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException + * @static + */ + public static function basic($field = 'email', $extraConditions = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->basic($field, $extraConditions); + } + + /** + * Perform a stateless HTTP Basic login attempt. + * + * @param string $field + * @param array $extraConditions + * @return \Symfony\Component\HttpFoundation\Response|null + * @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException + * @static + */ + public static function onceBasic($field = 'email', $extraConditions = []) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->onceBasic($field, $extraConditions); + } + + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * @param bool $remember + * @return bool + * @static + */ + public static function attempt($credentials = [], $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->attempt($credentials, $remember); + } + + /** + * Attempt to authenticate a user with credentials and additional callbacks. + * + * @param array $credentials + * @param array|callable|null $callbacks + * @param bool $remember + * @return bool + * @static + */ + public static function attemptWhen($credentials = [], $callbacks = null, $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->attemptWhen($credentials, $callbacks, $remember); + } + + /** + * Log the given user ID into the application. + * + * @param mixed $id + * @param bool $remember + * @return \App\Models\User|false + * @static + */ + public static function loginUsingId($id, $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->loginUsingId($id, $remember); + } + + /** + * Log a user into the application. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param bool $remember + * @return void + * @static + */ + public static function login($user, $remember = false) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->login($user, $remember); + } + + /** + * Log the user out of the application. + * + * @return void + * @static + */ + public static function logout() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->logout(); + } + + /** + * Log the user out of the application on their current device only. + * + * This method does not cycle the "remember" token. + * + * @return void + * @static + */ + public static function logoutCurrentDevice() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->logoutCurrentDevice(); + } + + /** + * Invalidate other sessions for the current user. + * + * The application must be using the AuthenticateSession middleware. + * + * @param string $password + * @return \App\Models\User|null + * @throws \Illuminate\Auth\AuthenticationException + * @static + */ + public static function logoutOtherDevices($password) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->logoutOtherDevices($password); + } + + /** + * Register an authentication attempt event listener. + * + * @param mixed $callback + * @return void + * @static + */ + public static function attempting($callback) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->attempting($callback); + } + + /** + * Get the last user we attempted to authenticate. + * + * @return \App\Models\User + * @static + */ + public static function getLastAttempted() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getLastAttempted(); + } + + /** + * Get a unique identifier for the auth session value. + * + * @return string + * @static + */ + public static function getName() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getName(); + } + + /** + * Get the name of the cookie used to store the "recaller". + * + * @return string + * @static + */ + public static function getRecallerName() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getRecallerName(); + } + + /** + * Determine if the user was authenticated via "remember me" cookie. + * + * @return bool + * @static + */ + public static function viaRemember() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->viaRemember(); + } + + /** + * Set the number of minutes the remember me cookie should be valid for. + * + * @param int $minutes + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function setRememberDuration($minutes) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->setRememberDuration($minutes); + } + + /** + * Get the cookie creator instance used by the guard. + * + * @return \Illuminate\Contracts\Cookie\QueueingFactory + * @throws \RuntimeException + * @static + */ + public static function getCookieJar() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getCookieJar(); + } + + /** + * Set the cookie creator instance used by the guard. + * + * @param \Illuminate\Contracts\Cookie\QueueingFactory $cookie + * @return void + * @static + */ + public static function setCookieJar($cookie) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->setCookieJar($cookie); + } + + /** + * Get the event dispatcher instance. + * + * @return \Illuminate\Contracts\Events\Dispatcher + * @static + */ + public static function getDispatcher() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getDispatcher(); + } + + /** + * Set the event dispatcher instance. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + * @static + */ + public static function setDispatcher($events) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->setDispatcher($events); + } + + /** + * Get the session store used by the guard. + * + * @return \Illuminate\Contracts\Session\Session + * @static + */ + public static function getSession() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getSession(); + } + + /** + * Return the currently cached user. + * + * @return \App\Models\User|null + * @static + */ + public static function getUser() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getUser(); + } + + /** + * Set the current user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function setUser($user) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->setUser($user); + } + + /** + * Get the current request instance. + * + * @return \Symfony\Component\HttpFoundation\Request + * @static + */ + public static function getRequest() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getRequest(); + } + + /** + * Set the current request instance. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function setRequest($request) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->setRequest($request); + } + + /** + * Get the timebox instance used by the guard. + * + * @return \Illuminate\Support\Timebox + * @static + */ + public static function getTimebox() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getTimebox(); + } + + /** + * Determine if the current user is authenticated. If not, throw an exception. + * + * @return \App\Models\User + * @throws \Illuminate\Auth\AuthenticationException + * @static + */ + public static function authenticate() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->authenticate(); + } + + /** + * Determine if the guard has a user instance. + * + * @return bool + * @static + */ + public static function hasUser() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->hasUser(); + } + + /** + * Determine if the current user is authenticated. + * + * @return bool + * @static + */ + public static function check() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->check(); + } + + /** + * Determine if the current user is a guest. + * + * @return bool + * @static + */ + public static function guest() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->guest(); + } + + /** + * Forget the current user. + * + * @return \Illuminate\Auth\SessionGuard + * @static + */ + public static function forgetUser() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->forgetUser(); + } + + /** + * Get the user provider used by the guard. + * + * @return \Illuminate\Contracts\Auth\UserProvider + * @static + */ + public static function getProvider() + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + return $instance->getProvider(); + } + + /** + * Set the user provider used by the guard. + * + * @param \Illuminate\Contracts\Auth\UserProvider $provider + * @return void + * @static + */ + public static function setProvider($provider) + { + /** @var \Illuminate\Auth\SessionGuard $instance */ + $instance->setProvider($provider); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Auth\SessionGuard::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Auth\SessionGuard::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Auth\SessionGuard::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Auth\SessionGuard::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\View\Compilers\BladeCompiler + */ + class Blade { + /** + * Compile the view at the given path. + * + * @param string|null $path + * @return void + * @static + */ + public static function compile($path = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->compile($path); + } + + /** + * Get the path currently being compiled. + * + * @return string + * @static + */ + public static function getPath() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getPath(); + } + + /** + * Set the path currently being compiled. + * + * @param string $path + * @return void + * @static + */ + public static function setPath($path) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->setPath($path); + } + + /** + * Compile the given Blade template contents. + * + * @param string $value + * @return string + * @static + */ + public static function compileString($value) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileString($value); + } + + /** + * Evaluate and render a Blade string to HTML. + * + * @param string $string + * @param array $data + * @param bool $deleteCachedView + * @return string + * @static + */ + public static function render($string, $data = [], $deleteCachedView = false) + { + return \Illuminate\View\Compilers\BladeCompiler::render($string, $data, $deleteCachedView); + } + + /** + * Render a component instance to HTML. + * + * @param \Illuminate\View\Component $component + * @return string + * @static + */ + public static function renderComponent($component) + { + return \Illuminate\View\Compilers\BladeCompiler::renderComponent($component); + } + + /** + * Strip the parentheses from the given expression. + * + * @param string $expression + * @return string + * @static + */ + public static function stripParentheses($expression) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->stripParentheses($expression); + } + + /** + * Register a custom Blade compiler. + * + * @param callable $compiler + * @return void + * @static + */ + public static function extend($compiler) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->extend($compiler); + } + + /** + * Get the extensions used by the compiler. + * + * @return array + * @static + */ + public static function getExtensions() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getExtensions(); + } + + /** + * Register an "if" statement directive. + * + * @param string $name + * @param callable $callback + * @return void + * @static + */ + public static function if($name, $callback) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->if($name, $callback); + } + + /** + * Check the result of a condition. + * + * @param string $name + * @param mixed $parameters + * @return bool + * @static + */ + public static function check($name, ...$parameters) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->check($name, ...$parameters); + } + + /** + * Register a class-based component alias directive. + * + * @param string $class + * @param string|null $alias + * @param string $prefix + * @return void + * @static + */ + public static function component($class, $alias = null, $prefix = '') + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->component($class, $alias, $prefix); + } + + /** + * Register an array of class-based components. + * + * @param array $components + * @param string $prefix + * @return void + * @static + */ + public static function components($components, $prefix = '') + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->components($components, $prefix); + } + + /** + * Get the registered class component aliases. + * + * @return array + * @static + */ + public static function getClassComponentAliases() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getClassComponentAliases(); + } + + /** + * Register a new anonymous component path. + * + * @param string $path + * @param string|null $prefix + * @return void + * @static + */ + public static function anonymousComponentPath($path, $prefix = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->anonymousComponentPath($path, $prefix); + } + + /** + * Register an anonymous component namespace. + * + * @param string $directory + * @param string|null $prefix + * @return void + * @static + */ + public static function anonymousComponentNamespace($directory, $prefix = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->anonymousComponentNamespace($directory, $prefix); + } + + /** + * Register a class-based component namespace. + * + * @param string $namespace + * @param string $prefix + * @return void + * @static + */ + public static function componentNamespace($namespace, $prefix) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->componentNamespace($namespace, $prefix); + } + + /** + * Get the registered anonymous component paths. + * + * @return array + * @static + */ + public static function getAnonymousComponentPaths() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getAnonymousComponentPaths(); + } + + /** + * Get the registered anonymous component namespaces. + * + * @return array + * @static + */ + public static function getAnonymousComponentNamespaces() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getAnonymousComponentNamespaces(); + } + + /** + * Get the registered class component namespaces. + * + * @return array + * @static + */ + public static function getClassComponentNamespaces() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getClassComponentNamespaces(); + } + + /** + * Register a component alias directive. + * + * @param string $path + * @param string|null $alias + * @return void + * @static + */ + public static function aliasComponent($path, $alias = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->aliasComponent($path, $alias); + } + + /** + * Register an include alias directive. + * + * @param string $path + * @param string|null $alias + * @return void + * @static + */ + public static function include($path, $alias = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->include($path, $alias); + } + + /** + * Register an include alias directive. + * + * @param string $path + * @param string|null $alias + * @return void + * @static + */ + public static function aliasInclude($path, $alias = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->aliasInclude($path, $alias); + } + + /** + * Register a handler for custom directives, binding the handler to the compiler. + * + * @param string $name + * @param callable $handler + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function bindDirective($name, $handler) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->bindDirective($name, $handler); + } + + /** + * Register a handler for custom directives. + * + * @param string $name + * @param callable $handler + * @param bool $bind + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function directive($name, $handler, $bind = false) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->directive($name, $handler, $bind); + } + + /** + * Get the list of custom directives. + * + * @return array + * @static + */ + public static function getCustomDirectives() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getCustomDirectives(); + } + + /** + * Indicate that the following callable should be used to prepare strings for compilation. + * + * @param callable $callback + * @return \Illuminate\View\Compilers\BladeCompiler + * @static + */ + public static function prepareStringsForCompilationUsing($callback) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->prepareStringsForCompilationUsing($callback); + } + + /** + * Register a new precompiler. + * + * @param callable $precompiler + * @return void + * @static + */ + public static function precompiler($precompiler) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->precompiler($precompiler); + } + + /** + * Set the echo format to be used by the compiler. + * + * @param string $format + * @return void + * @static + */ + public static function setEchoFormat($format) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->setEchoFormat($format); + } + + /** + * Set the "echo" format to double encode entities. + * + * @return void + * @static + */ + public static function withDoubleEncoding() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->withDoubleEncoding(); + } + + /** + * Set the "echo" format to not double encode entities. + * + * @return void + * @static + */ + public static function withoutDoubleEncoding() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->withoutDoubleEncoding(); + } + + /** + * Indicate that component tags should not be compiled. + * + * @return void + * @static + */ + public static function withoutComponentTags() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->withoutComponentTags(); + } + + /** + * Get the path to the compiled version of a view. + * + * @param string $path + * @return string + * @static + */ + public static function getCompiledPath($path) + { + //Method inherited from \Illuminate\View\Compilers\Compiler + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->getCompiledPath($path); + } + + /** + * Determine if the view at the given path is expired. + * + * @param string $path + * @return bool + * @throws \ErrorException + * @static + */ + public static function isExpired($path) + { + //Method inherited from \Illuminate\View\Compilers\Compiler + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->isExpired($path); + } + + /** + * Get a new component hash for a component name. + * + * @param string $component + * @return string + * @static + */ + public static function newComponentHash($component) + { + return \Illuminate\View\Compilers\BladeCompiler::newComponentHash($component); + } + + /** + * Compile a class component opening. + * + * @param string $component + * @param string $alias + * @param string $data + * @param string $hash + * @return string + * @static + */ + public static function compileClassComponentOpening($component, $alias, $data, $hash) + { + return \Illuminate\View\Compilers\BladeCompiler::compileClassComponentOpening($component, $alias, $data, $hash); + } + + /** + * Compile the end-component statements into valid PHP. + * + * @return string + * @static + */ + public static function compileEndComponentClass() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileEndComponentClass(); + } + + /** + * Sanitize the given component attribute value. + * + * @param mixed $value + * @return mixed + * @static + */ + public static function sanitizeComponentAttribute($value) + { + return \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute($value); + } + + /** + * Compile an end-once block into valid PHP. + * + * @return string + * @static + */ + public static function compileEndOnce() + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileEndOnce(); + } + + /** + * Add a handler to be executed before echoing a given class. + * + * @param string|callable $class + * @param callable|null $handler + * @return void + * @static + */ + public static function stringable($class, $handler = null) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + $instance->stringable($class, $handler); + } + + /** + * Compile Blade echos into valid PHP. + * + * @param string $value + * @return string + * @static + */ + public static function compileEchos($value) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->compileEchos($value); + } + + /** + * Apply the echo handler for the value if it exists. + * + * @param string $value + * @return string + * @static + */ + public static function applyEchoHandler($value) + { + /** @var \Illuminate\View\Compilers\BladeCompiler $instance */ + return $instance->applyEchoHandler($value); + } + + } + /** + * + * + * @method static mixed auth(\Illuminate\Http\Request $request) + * @method static mixed validAuthenticationResponse(\Illuminate\Http\Request $request, mixed $result) + * @method static void broadcast(array $channels, string $event, array $payload = []) + * @method static array|null resolveAuthenticatedUser(\Illuminate\Http\Request $request) + * @method static void resolveAuthenticatedUserUsing(\Closure $callback) + * @method static \Illuminate\Broadcasting\Broadcasters\Broadcaster channel(\Illuminate\Contracts\Broadcasting\HasBroadcastChannel|string $channel, callable|string $callback, array $options = []) + * @method static \Illuminate\Support\Collection getChannels() + * @see \Illuminate\Broadcasting\BroadcastManager + * @see \Illuminate\Broadcasting\Broadcasters\Broadcaster + */ + class Broadcast { + /** + * Register the routes for handling broadcast channel authentication and sockets. + * + * @param array|null $attributes + * @return void + * @static + */ + public static function routes($attributes = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->routes($attributes); + } + + /** + * Register the routes for handling broadcast user authentication. + * + * @param array|null $attributes + * @return void + * @static + */ + public static function userRoutes($attributes = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->userRoutes($attributes); + } + + /** + * Register the routes for handling broadcast authentication and sockets. + * + * Alias of "routes" method. + * + * @param array|null $attributes + * @return void + * @static + */ + public static function channelRoutes($attributes = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->channelRoutes($attributes); + } + + /** + * Get the socket ID for the given request. + * + * @param \Illuminate\Http\Request|null $request + * @return string|null + * @static + */ + public static function socket($request = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->socket($request); + } + + /** + * Begin sending an anonymous broadcast to the given channels. + * + * @static + */ + public static function on($channels) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->on($channels); + } + + /** + * Begin sending an anonymous broadcast to the given private channels. + * + * @static + */ + public static function private($channel) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->private($channel); + } + + /** + * Begin sending an anonymous broadcast to the given presence channels. + * + * @static + */ + public static function presence($channel) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->presence($channel); + } + + /** + * Begin broadcasting an event. + * + * @param mixed|null $event + * @return \Illuminate\Broadcasting\PendingBroadcast + * @static + */ + public static function event($event = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->event($event); + } + + /** + * Queue the given event for broadcast. + * + * @param mixed $event + * @return void + * @static + */ + public static function queue($event) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->queue($event); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @static + */ + public static function connection($driver = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->connection($driver); + } + + /** + * Get a driver instance. + * + * @param string|null $name + * @return mixed + * @static + */ + public static function driver($name = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->driver($name); + } + + /** + * Get a Pusher instance for the given configuration. + * + * @param array $config + * @return \Pusher\Pusher + * @static + */ + public static function pusher($config) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->pusher($config); + } + + /** + * Get an Ably instance for the given configuration. + * + * @param array $config + * @return \Ably\AblyRest + * @static + */ + public static function ably($config) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->ably($config); + } + + /** + * Get the default driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Disconnect the given disk and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Broadcasting\BroadcastManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + * @static + */ + public static function getApplication() + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->getApplication(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Broadcasting\BroadcastManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->setApplication($app); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Broadcasting\BroadcastManager + * @static + */ + public static function forgetDrivers() + { + /** @var \Illuminate\Broadcasting\BroadcastManager $instance */ + return $instance->forgetDrivers(); + } + + } + /** + * + * + * @see \Illuminate\Bus\Dispatcher + * @see \Illuminate\Support\Testing\Fakes\BusFake + */ + class Bus { + /** + * Dispatch a command to its appropriate handler. + * + * @param mixed $command + * @return mixed + * @static + */ + public static function dispatch($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatch($command); + } + + /** + * Dispatch a command to its appropriate handler in the current process. + * + * Queueable jobs will be dispatched to the "sync" queue. + * + * @param mixed $command + * @param mixed $handler + * @return mixed + * @static + */ + public static function dispatchSync($command, $handler = null) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatchSync($command, $handler); + } + + /** + * Dispatch a command to its appropriate handler in the current process without using the synchronous queue. + * + * @param mixed $command + * @param mixed $handler + * @return mixed + * @static + */ + public static function dispatchNow($command, $handler = null) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatchNow($command, $handler); + } + + /** + * Attempt to find the batch with the given ID. + * + * @param string $batchId + * @return \Illuminate\Bus\Batch|null + * @static + */ + public static function findBatch($batchId) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->findBatch($batchId); + } + + /** + * Create a new batch of queueable jobs. + * + * @param \Illuminate\Support\Collection|array|mixed $jobs + * @return \Illuminate\Bus\PendingBatch + * @static + */ + public static function batch($jobs) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->batch($jobs); + } + + /** + * Create a new chain of queueable jobs. + * + * @param \Illuminate\Support\Collection|array $jobs + * @return \Illuminate\Foundation\Bus\PendingChain + * @static + */ + public static function chain($jobs) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->chain($jobs); + } + + /** + * Determine if the given command has a handler. + * + * @param mixed $command + * @return bool + * @static + */ + public static function hasCommandHandler($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->hasCommandHandler($command); + } + + /** + * Retrieve the handler for a command. + * + * @param mixed $command + * @return bool|mixed + * @static + */ + public static function getCommandHandler($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->getCommandHandler($command); + } + + /** + * Dispatch a command to its appropriate handler behind a queue. + * + * @param mixed $command + * @return mixed + * @throws \RuntimeException + * @static + */ + public static function dispatchToQueue($command) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->dispatchToQueue($command); + } + + /** + * Dispatch a command to its appropriate handler after the current process. + * + * @param mixed $command + * @param mixed $handler + * @return void + * @static + */ + public static function dispatchAfterResponse($command, $handler = null) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + $instance->dispatchAfterResponse($command, $handler); + } + + /** + * Set the pipes through which commands should be piped before dispatching. + * + * @param array $pipes + * @return \Illuminate\Bus\Dispatcher + * @static + */ + public static function pipeThrough($pipes) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->pipeThrough($pipes); + } + + /** + * Map a command to a handler. + * + * @param array $map + * @return \Illuminate\Bus\Dispatcher + * @static + */ + public static function map($map) + { + /** @var \Illuminate\Bus\Dispatcher $instance */ + return $instance->map($map); + } + + /** + * Specify the jobs that should be dispatched instead of faked. + * + * @param array|string $jobsToDispatch + * @return \Illuminate\Support\Testing\Fakes\BusFake + * @static + */ + public static function except($jobsToDispatch) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->except($jobsToDispatch); + } + + /** + * Assert if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatched($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatched($command, $callback); + } + + /** + * Assert if a job was pushed a number of times. + * + * @param string|\Closure $command + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedTimes($command, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedTimes($command, $times); + } + + /** + * Determine if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatched($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNotDispatched($command, $callback); + } + + /** + * Assert that no jobs were dispatched. + * + * @return void + * @static + */ + public static function assertNothingDispatched() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingDispatched(); + } + + /** + * Assert if a job was explicitly dispatched synchronously based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatchedSync($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedSync($command, $callback); + } + + /** + * Assert if a job was pushed synchronously a number of times. + * + * @param string|\Closure $command + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedSyncTimes($command, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedSyncTimes($command, $times); + } + + /** + * Determine if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatchedSync($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNotDispatchedSync($command, $callback); + } + + /** + * Assert if a job was dispatched after the response was sent based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatchedAfterResponse($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedAfterResponse($command, $callback); + } + + /** + * Assert if a job was pushed after the response was sent a number of times. + * + * @param string|\Closure $command + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedAfterResponseTimes($command, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedAfterResponseTimes($command, $times); + } + + /** + * Determine if a job was dispatched based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatchedAfterResponse($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNotDispatchedAfterResponse($command, $callback); + } + + /** + * Assert if a chain of jobs was dispatched. + * + * @param array $expectedChain + * @return void + * @static + */ + public static function assertChained($expectedChain) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertChained($expectedChain); + } + + /** + * Assert no chained jobs was dispatched. + * + * @return void + * @static + */ + public static function assertNothingChained() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingChained(); + } + + /** + * Assert if a job was dispatched with an empty chain based on a truth-test callback. + * + * @param string|\Closure $command + * @param callable|null $callback + * @return void + * @static + */ + public static function assertDispatchedWithoutChain($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertDispatchedWithoutChain($command, $callback); + } + + /** + * Create a new assertion about a chained batch. + * + * @param \Closure $callback + * @return \Illuminate\Support\Testing\Fakes\ChainedBatchTruthTest + * @static + */ + public static function chainedBatch($callback) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->chainedBatch($callback); + } + + /** + * Assert if a batch was dispatched based on a truth-test callback. + * + * @param callable $callback + * @return void + * @static + */ + public static function assertBatched($callback) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertBatched($callback); + } + + /** + * Assert the number of batches that have been dispatched. + * + * @param int $count + * @return void + * @static + */ + public static function assertBatchCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertBatchCount($count); + } + + /** + * Assert that no batched jobs were dispatched. + * + * @return void + * @static + */ + public static function assertNothingBatched() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingBatched(); + } + + /** + * Assert that no jobs were dispatched, chained, or batched. + * + * @return void + * @static + */ + public static function assertNothingPlaced() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + $instance->assertNothingPlaced(); + } + + /** + * Get all of the jobs matching a truth-test callback. + * + * @param string $command + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatched($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatched($command, $callback); + } + + /** + * Get all of the jobs dispatched synchronously matching a truth-test callback. + * + * @param string $command + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatchedSync($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchedSync($command, $callback); + } + + /** + * Get all of the jobs dispatched after the response was sent matching a truth-test callback. + * + * @param string $command + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatchedAfterResponse($command, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchedAfterResponse($command, $callback); + } + + /** + * Get all of the pending batches matching a truth-test callback. + * + * @param callable $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function batched($callback) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->batched($callback); + } + + /** + * Determine if there are any stored commands for a given class. + * + * @param string $command + * @return bool + * @static + */ + public static function hasDispatched($command) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->hasDispatched($command); + } + + /** + * Determine if there are any stored commands for a given class. + * + * @param string $command + * @return bool + * @static + */ + public static function hasDispatchedSync($command) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->hasDispatchedSync($command); + } + + /** + * Determine if there are any stored commands for a given class. + * + * @param string $command + * @return bool + * @static + */ + public static function hasDispatchedAfterResponse($command) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->hasDispatchedAfterResponse($command); + } + + /** + * Dispatch an empty job batch for testing. + * + * @param string $name + * @return \Illuminate\Bus\Batch + * @static + */ + public static function dispatchFakeBatch($name = '') + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchFakeBatch($name); + } + + /** + * Record the fake pending batch dispatch. + * + * @param \Illuminate\Bus\PendingBatch $pendingBatch + * @return \Illuminate\Bus\Batch + * @static + */ + public static function recordPendingBatch($pendingBatch) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->recordPendingBatch($pendingBatch); + } + + /** + * Specify if commands should be serialized and restored when being batched. + * + * @param bool $serializeAndRestore + * @return \Illuminate\Support\Testing\Fakes\BusFake + * @static + */ + public static function serializeAndRestore($serializeAndRestore = true) + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->serializeAndRestore($serializeAndRestore); + } + + /** + * Get the batches that have been dispatched. + * + * @return array + * @static + */ + public static function dispatchedBatches() + { + /** @var \Illuminate\Support\Testing\Fakes\BusFake $instance */ + return $instance->dispatchedBatches(); + } + + } + /** + * + * + * @see \Illuminate\Cache\CacheManager + * @see \Illuminate\Cache\Repository + */ + class Cache { + /** + * Get a cache store instance by name, wrapped in a repository. + * + * @param string|null $name + * @return \Illuminate\Contracts\Cache\Repository + * @static + */ + public static function store($name = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->store($name); + } + + /** + * Get a cache driver instance. + * + * @param string|null $driver + * @return \Illuminate\Contracts\Cache\Repository + * @static + */ + public static function driver($driver = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->driver($driver); + } + + /** + * Resolve the given store. + * + * @param string $name + * @return \Illuminate\Contracts\Cache\Repository + * @throws \InvalidArgumentException + * @static + */ + public static function resolve($name) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->resolve($name); + } + + /** + * Build a cache repository with the given configuration. + * + * @param array $config + * @return \Illuminate\Cache\Repository + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->build($config); + } + + /** + * Create a new cache repository with the given implementation. + * + * @param \Illuminate\Contracts\Cache\Store $store + * @param array $config + * @return \Illuminate\Cache\Repository + * @static + */ + public static function repository($store, $config = []) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->repository($store, $config); + } + + /** + * Re-set the event dispatcher on all resolved cache repositories. + * + * @return void + * @static + */ + public static function refreshEventDispatcher() + { + /** @var \Illuminate\Cache\CacheManager $instance */ + $instance->refreshEventDispatcher(); + } + + /** + * Get the default cache driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default cache driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Unset the given driver instances. + * + * @param array|string|null $name + * @return \Illuminate\Cache\CacheManager + * @static + */ + public static function forgetDriver($name = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->forgetDriver($name); + } + + /** + * Disconnect the given driver and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @param-closure-this $this $callback + * @return \Illuminate\Cache\CacheManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Cache\CacheManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Cache\CacheManager $instance */ + return $instance->setApplication($app); + } + + /** + * Determine if an item exists in the cache. + * + * @param array|string $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->has($key); + } + + /** + * Determine if an item doesn't exist in the cache. + * + * @param string $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->missing($key); + } + + /** + * Retrieve an item from the cache by key. + * + * @param array|string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->get($key, $default); + } + + /** + * Retrieve multiple items from the cache by key. + * + * Items not found in the cache will have a null value. + * + * @param array $keys + * @return array + * @static + */ + public static function many($keys) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->many($keys); + } + + /** + * Obtains multiple cache items by their unique keys. + * + * @return iterable + * @param iterable $keys A list of keys that can be obtained in a single operation. + * @param mixed $default Default value to return for keys that do not exist. + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + * @static + */ + public static function getMultiple($keys, $default = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getMultiple($keys, $default); + } + + /** + * Retrieve an item from the cache and delete it. + * + * @param array|string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pull($key, $default = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->pull($key, $default); + } + + /** + * Store an item in the cache. + * + * @param array|string $key + * @param mixed $value + * @param \DateTimeInterface|\DateInterval|int|null $ttl + * @return bool + * @static + */ + public static function put($key, $value, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->put($key, $value, $ttl); + } + + /** + * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. + * + * @return bool + * @param string $key The key of the item to store. + * @param mixed $value The value of the item to store, must be serializable. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * @return bool True on success and false on failure. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + * @static + */ + public static function set($key, $value, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->set($key, $value, $ttl); + } + + /** + * Store multiple items in the cache for a given number of seconds. + * + * @param array $values + * @param \DateTimeInterface|\DateInterval|int|null $ttl + * @return bool + * @static + */ + public static function putMany($values, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->putMany($values, $ttl); + } + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @return bool + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * @return bool True on success and false on failure. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + * @static + */ + public static function setMultiple($values, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->setMultiple($values, $ttl); + } + + /** + * Store an item in the cache if the key does not exist. + * + * @param string $key + * @param mixed $value + * @param \DateTimeInterface|\DateInterval|int|null $ttl + * @return bool + * @static + */ + public static function add($key, $value, $ttl = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->add($key, $value, $ttl); + } + + /** + * Increment the value of an item in the cache. + * + * @param string $key + * @param mixed $value + * @return int|bool + * @static + */ + public static function increment($key, $value = 1) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->increment($key, $value); + } + + /** + * Decrement the value of an item in the cache. + * + * @param string $key + * @param mixed $value + * @return int|bool + * @static + */ + public static function decrement($key, $value = 1) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->decrement($key, $value); + } + + /** + * Store an item in the cache indefinitely. + * + * @param string $key + * @param mixed $value + * @return bool + * @static + */ + public static function forever($key, $value) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->forever($key, $value); + } + + /** + * Get an item from the cache, or execute the given Closure and store the result. + * + * @template TCacheValue + * @param string $key + * @param \Closure|\DateTimeInterface|\DateInterval|int|null $ttl + * @param \Closure(): TCacheValue $callback + * @return TCacheValue + * @static + */ + public static function remember($key, $ttl, $callback) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->remember($key, $ttl, $callback); + } + + /** + * Get an item from the cache, or execute the given Closure and store the result forever. + * + * @template TCacheValue + * @param string $key + * @param \Closure(): TCacheValue $callback + * @return TCacheValue + * @static + */ + public static function sear($key, $callback) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->sear($key, $callback); + } + + /** + * Get an item from the cache, or execute the given Closure and store the result forever. + * + * @template TCacheValue + * @param string $key + * @param \Closure(): TCacheValue $callback + * @return TCacheValue + * @static + */ + public static function rememberForever($key, $callback) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->rememberForever($key, $callback); + } + + /** + * Retrieve an item from the cache by key, refreshing it in the background if it is stale. + * + * @template TCacheValue + * @param string $key + * @param array{ 0: \DateTimeInterface|\DateInterval|int, 1: \DateTimeInterface|\DateInterval|int } $ttl + * @param (callable(): TCacheValue) $callback + * @param array{ seconds?: int, owner?: string }|null $lock + * @return TCacheValue + * @static + */ + public static function flexible($key, $ttl, $callback, $lock = null) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->flexible($key, $ttl, $callback, $lock); + } + + /** + * Remove an item from the cache. + * + * @param string $key + * @return bool + * @static + */ + public static function forget($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->forget($key); + } + + /** + * Delete an item from the cache by its unique key. + * + * @return bool + * @param string $key The unique cache key of the item to delete. + * @return bool True if the item was successfully removed. False if there was an error. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + * @static + */ + public static function delete($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->delete($key); + } + + /** + * Deletes multiple cache items in a single operation. + * + * @return bool + * @param iterable $keys A list of string-based keys to be deleted. + * @return bool True if the items were successfully removed. False if there was an error. + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + * @static + */ + public static function deleteMultiple($keys) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->deleteMultiple($keys); + } + + /** + * Wipes clean the entire cache's keys. + * + * @return bool + * @return bool True on success and false on failure. + * @static + */ + public static function clear() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->clear(); + } + + /** + * Begin executing a new tags operation if the store supports it. + * + * @param array|mixed $names + * @return \Illuminate\Cache\TaggedCache + * @throws \BadMethodCallException + * @static + */ + public static function tags($names) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->tags($names); + } + + /** + * Get the name of the cache store. + * + * @return string|null + * @static + */ + public static function getName() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getName(); + } + + /** + * Determine if the current store supports tags. + * + * @return bool + * @static + */ + public static function supportsTags() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->supportsTags(); + } + + /** + * Get the default cache time. + * + * @return int|null + * @static + */ + public static function getDefaultCacheTime() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getDefaultCacheTime(); + } + + /** + * Set the default cache time in seconds. + * + * @param int|null $seconds + * @return \Illuminate\Cache\Repository + * @static + */ + public static function setDefaultCacheTime($seconds) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->setDefaultCacheTime($seconds); + } + + /** + * Get the cache store implementation. + * + * @return \Illuminate\Contracts\Cache\Store + * @static + */ + public static function getStore() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getStore(); + } + + /** + * Set the cache store implementation. + * + * @param \Illuminate\Contracts\Cache\Store $store + * @return static + * @static + */ + public static function setStore($store) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->setStore($store); + } + + /** + * Get the event dispatcher instance. + * + * @return \Illuminate\Contracts\Events\Dispatcher|null + * @static + */ + public static function getEventDispatcher() + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->getEventDispatcher(); + } + + /** + * Set the event dispatcher instance. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + * @static + */ + public static function setEventDispatcher($events) + { + /** @var \Illuminate\Cache\Repository $instance */ + $instance->setEventDispatcher($events); + } + + /** + * Determine if a cached value exists. + * + * @param string $key + * @return bool + * @static + */ + public static function offsetExists($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->offsetExists($key); + } + + /** + * Retrieve an item from the cache by key. + * + * @param string $key + * @return mixed + * @static + */ + public static function offsetGet($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->offsetGet($key); + } + + /** + * Store an item in the cache for the default time. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($key, $value) + { + /** @var \Illuminate\Cache\Repository $instance */ + $instance->offsetSet($key, $value); + } + + /** + * Remove an item from the cache. + * + * @param string $key + * @return void + * @static + */ + public static function offsetUnset($key) + { + /** @var \Illuminate\Cache\Repository $instance */ + $instance->offsetUnset($key); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Cache\Repository::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Cache\Repository::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Cache\Repository::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Cache\Repository::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Cache\Repository $instance */ + return $instance->macroCall($method, $parameters); + } + + /** + * Get a lock instance. + * + * @param string $name + * @param int $seconds + * @param string|null $owner + * @return \Illuminate\Contracts\Cache\Lock + * @static + */ + public static function lock($name, $seconds = 0, $owner = null) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->lock($name, $seconds, $owner); + } + + /** + * Restore a lock instance using the owner identifier. + * + * @param string $name + * @param string $owner + * @return \Illuminate\Contracts\Cache\Lock + * @static + */ + public static function restoreLock($name, $owner) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->restoreLock($name, $owner); + } + + /** + * Remove an item from the cache if it is expired. + * + * @param string $key + * @return bool + * @static + */ + public static function forgetIfExpired($key) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->forgetIfExpired($key); + } + + /** + * Remove all items from the cache. + * + * @return bool + * @static + */ + public static function flush() + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->flush(); + } + + /** + * Get the underlying database connection. + * + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function getConnection() + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->getConnection(); + } + + /** + * Specify the name of the connection that should be used to manage locks. + * + * @param \Illuminate\Database\ConnectionInterface $connection + * @return \Illuminate\Cache\DatabaseStore + * @static + */ + public static function setLockConnection($connection) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->setLockConnection($connection); + } + + /** + * Get the cache key prefix. + * + * @return string + * @static + */ + public static function getPrefix() + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + return $instance->getPrefix(); + } + + /** + * Set the cache key prefix. + * + * @param string $prefix + * @return void + * @static + */ + public static function setPrefix($prefix) + { + /** @var \Illuminate\Cache\DatabaseStore $instance */ + $instance->setPrefix($prefix); + } + + } + /** + * + * + * @method static array run(\Closure|array $tasks) + * @method static \Illuminate\Support\Defer\DeferredCallback defer(\Closure|array $tasks) + * @see \Illuminate\Concurrency\ConcurrencyManager + */ + class Concurrency { + /** + * Get a driver instance by name. + * + * @param string|null $name + * @return mixed + * @static + */ + public static function driver($name = null) + { + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->driver($name); + } + + /** + * Create an instance of the process concurrency driver. + * + * @param array $config + * @return \Illuminate\Concurrency\ProcessDriver + * @static + */ + public static function createProcessDriver($config) + { + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->createProcessDriver($config); + } + + /** + * Create an instance of the fork concurrency driver. + * + * @param array $config + * @return \Illuminate\Concurrency\ForkDriver + * @throws \RuntimeException + * @static + */ + public static function createForkDriver($config) + { + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->createForkDriver($config); + } + + /** + * Create an instance of the sync concurrency driver. + * + * @param array $config + * @return \Illuminate\Concurrency\SyncDriver + * @static + */ + public static function createSyncDriver($config) + { + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->createSyncDriver($config); + } + + /** + * Get the default instance name. + * + * @return string + * @static + */ + public static function getDefaultInstance() + { + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->getDefaultInstance(); + } + + /** + * Set the default instance name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultInstance($name) + { + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + $instance->setDefaultInstance($name); + } + + /** + * Get the instance specific configuration. + * + * @param string $name + * @return array + * @static + */ + public static function getInstanceConfig($name) + { + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->getInstanceConfig($name); + } + + /** + * Get an instance by name. + * + * @param string|null $name + * @return mixed + * @static + */ + public static function instance($name = null) + { + //Method inherited from \Illuminate\Support\MultipleInstanceManager + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->instance($name); + } + + /** + * Unset the given instances. + * + * @param array|string|null $name + * @return \Illuminate\Concurrency\ConcurrencyManager + * @static + */ + public static function forgetInstance($name = null) + { + //Method inherited from \Illuminate\Support\MultipleInstanceManager + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->forgetInstance($name); + } + + /** + * Disconnect the given instance and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + //Method inherited from \Illuminate\Support\MultipleInstanceManager + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom instance creator Closure. + * + * @param string $name + * @param \Closure $callback + * @param-closure-this $this $callback + * @return \Illuminate\Concurrency\ConcurrencyManager + * @static + */ + public static function extend($name, $callback) + { + //Method inherited from \Illuminate\Support\MultipleInstanceManager + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->extend($name, $callback); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Concurrency\ConcurrencyManager + * @static + */ + public static function setApplication($app) + { + //Method inherited from \Illuminate\Support\MultipleInstanceManager + /** @var \Illuminate\Concurrency\ConcurrencyManager $instance */ + return $instance->setApplication($app); + } + + } + /** + * + * + * @see \Illuminate\Config\Repository + */ + class Config { + /** + * Determine if the given configuration value exists. + * + * @param string $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->has($key); + } + + /** + * Get the specified configuration value. + * + * @param array|string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->get($key, $default); + } + + /** + * Get many configuration values. + * + * @param array $keys + * @return array + * @static + */ + public static function getMany($keys) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->getMany($keys); + } + + /** + * Get the specified string configuration value. + * + * @param string $key + * @param (\Closure():(string|null))|string|null $default + * @return string + * @static + */ + public static function string($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->string($key, $default); + } + + /** + * Get the specified integer configuration value. + * + * @param string $key + * @param (\Closure():(int|null))|int|null $default + * @return int + * @static + */ + public static function integer($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->integer($key, $default); + } + + /** + * Get the specified float configuration value. + * + * @param string $key + * @param (\Closure():(float|null))|float|null $default + * @return float + * @static + */ + public static function float($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->float($key, $default); + } + + /** + * Get the specified boolean configuration value. + * + * @param string $key + * @param (\Closure():(bool|null))|bool|null $default + * @return bool + * @static + */ + public static function boolean($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->boolean($key, $default); + } + + /** + * Get the specified array configuration value. + * + * @param string $key + * @param (\Closure():(array|null))|array|null $default + * @return array + * @static + */ + public static function array($key, $default = null) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->array($key, $default); + } + + /** + * Set a given configuration value. + * + * @param array|string $key + * @param mixed $value + * @return void + * @static + */ + public static function set($key, $value = null) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->set($key, $value); + } + + /** + * Prepend a value onto an array configuration value. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function prepend($key, $value) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->prepend($key, $value); + } + + /** + * Push a value onto an array configuration value. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function push($key, $value) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->push($key, $value); + } + + /** + * Get all of the configuration items for the application. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->all(); + } + + /** + * Determine if the given configuration option exists. + * + * @param string $key + * @return bool + * @static + */ + public static function offsetExists($key) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->offsetExists($key); + } + + /** + * Get a configuration option. + * + * @param string $key + * @return mixed + * @static + */ + public static function offsetGet($key) + { + /** @var \Illuminate\Config\Repository $instance */ + return $instance->offsetGet($key); + } + + /** + * Set a configuration option. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($key, $value) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->offsetSet($key, $value); + } + + /** + * Unset a configuration option. + * + * @param string $key + * @return void + * @static + */ + public static function offsetUnset($key) + { + /** @var \Illuminate\Config\Repository $instance */ + $instance->offsetUnset($key); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Config\Repository::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Config\Repository::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Config\Repository::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Config\Repository::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Log\Context\Repository + */ + class Context { + /** + * Determine if the given key exists. + * + * @param string $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->has($key); + } + + /** + * Determine if the given key is missing. + * + * @param string $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->missing($key); + } + + /** + * Determine if the given key exists within the hidden context data. + * + * @param string $key + * @return bool + * @static + */ + public static function hasHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hasHidden($key); + } + + /** + * Determine if the given key is missing within the hidden context data. + * + * @param string $key + * @return bool + * @static + */ + public static function missingHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->missingHidden($key); + } + + /** + * Retrieve all the context data. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->all(); + } + + /** + * Retrieve all the hidden context data. + * + * @return array + * @static + */ + public static function allHidden() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->allHidden(); + } + + /** + * Retrieve the given key's value. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->get($key, $default); + } + + /** + * Retrieve the given key's hidden value. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function getHidden($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->getHidden($key, $default); + } + + /** + * Retrieve the given key's value and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pull($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pull($key, $default); + } + + /** + * Retrieve the given key's hidden value and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pullHidden($key, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pullHidden($key, $default); + } + + /** + * Retrieve only the values of the given keys. + * + * @param array $keys + * @return array + * @static + */ + public static function only($keys) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->only($keys); + } + + /** + * Retrieve only the hidden values of the given keys. + * + * @param array $keys + * @return array + * @static + */ + public static function onlyHidden($keys) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->onlyHidden($keys); + } + + /** + * Add a context value. + * + * @param string|array $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function add($key, $value = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->add($key, $value); + } + + /** + * Add a hidden context value. + * + * @param string|array $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function addHidden($key, $value = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->addHidden($key, $value); + } + + /** + * Forget the given context key. + * + * @param string|array $key + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function forget($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->forget($key); + } + + /** + * Forget the given hidden context key. + * + * @param string|array $key + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function forgetHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->forgetHidden($key); + } + + /** + * Add a context value if it does not exist yet. + * + * @param string $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function addIf($key, $value) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->addIf($key, $value); + } + + /** + * Add a hidden context value if it does not exist yet. + * + * @param string $key + * @param mixed $value + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function addHiddenIf($key, $value) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->addHiddenIf($key, $value); + } + + /** + * Push the given values onto the key's stack. + * + * @param string $key + * @param mixed $values + * @return \Illuminate\Log\Context\Repository + * @throws \RuntimeException + * @static + */ + public static function push($key, ...$values) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->push($key, ...$values); + } + + /** + * Pop the latest value from the key's stack. + * + * @param string $key + * @return mixed + * @throws \RuntimeException + * @static + */ + public static function pop($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pop($key); + } + + /** + * Push the given hidden values onto the key's stack. + * + * @param string $key + * @param mixed $values + * @return \Illuminate\Log\Context\Repository + * @throws \RuntimeException + * @static + */ + public static function pushHidden($key, ...$values) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->pushHidden($key, ...$values); + } + + /** + * Pop the latest hidden value from the key's stack. + * + * @param string $key + * @return mixed + * @throws \RuntimeException + * @static + */ + public static function popHidden($key) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->popHidden($key); + } + + /** + * Increment a context counter. + * + * @param string $key + * @param int $amount + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function increment($key, $amount = 1) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->increment($key, $amount); + } + + /** + * Decrement a context counter. + * + * @param string $key + * @param int $amount + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function decrement($key, $amount = 1) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->decrement($key, $amount); + } + + /** + * Determine if the given value is in the given stack. + * + * @param string $key + * @param mixed $value + * @param bool $strict + * @return bool + * @throws \RuntimeException + * @static + */ + public static function stackContains($key, $value, $strict = false) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->stackContains($key, $value, $strict); + } + + /** + * Determine if the given value is in the given hidden stack. + * + * @param string $key + * @param mixed $value + * @param bool $strict + * @return bool + * @throws \RuntimeException + * @static + */ + public static function hiddenStackContains($key, $value, $strict = false) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hiddenStackContains($key, $value, $strict); + } + + /** + * Run the callback function with the given context values and restore the original context state when complete. + * + * @param callable $callback + * @param array $data + * @param array $hidden + * @return mixed + * @static + */ + public static function scope($callback, $data = [], $hidden = []) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->scope($callback, $data, $hidden); + } + + /** + * Determine if the repository is empty. + * + * @return bool + * @static + */ + public static function isEmpty() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->isEmpty(); + } + + /** + * Execute the given callback when context is about to be dehydrated. + * + * @param callable $callback + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function dehydrating($callback) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->dehydrating($callback); + } + + /** + * Execute the given callback when context has been hydrated. + * + * @param callable $callback + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function hydrated($callback) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hydrated($callback); + } + + /** + * Handle unserialize exceptions using the given callback. + * + * @param callable|null $callback + * @return static + * @static + */ + public static function handleUnserializeExceptionsUsing($callback) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->handleUnserializeExceptionsUsing($callback); + } + + /** + * Flush all context data. + * + * @return \Illuminate\Log\Context\Repository + * @static + */ + public static function flush() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->flush(); + } + + /** + * Dehydrate the context data. + * + * @internal + * @return \Illuminate\Log\Context\?array + * @static + */ + public static function dehydrate() + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->dehydrate(); + } + + /** + * Hydrate the context instance. + * + * @internal + * @param \Illuminate\Log\Context\?array $context + * @return \Illuminate\Log\Context\Repository + * @throws \RuntimeException + * @static + */ + public static function hydrate($context) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->hydrate($context); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Log\Context\Repository::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Log\Context\Repository::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Log\Context\Repository::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Log\Context\Repository::flushMacros(); + } + + /** + * Restore the model from the model identifier instance. + * + * @param \Illuminate\Contracts\Database\ModelIdentifier $value + * @return \Illuminate\Database\Eloquent\Model + * @static + */ + public static function restoreModel($value) + { + /** @var \Illuminate\Log\Context\Repository $instance */ + return $instance->restoreModel($value); + } + + } + /** + * + * + * @see \Illuminate\Cookie\CookieJar + */ + class Cookie { + /** + * Create a new cookie instance. + * + * @param string $name + * @param string $value + * @param int $minutes + * @param string|null $path + * @param string|null $domain + * @param bool|null $secure + * @param bool $httpOnly + * @param bool $raw + * @param string|null $sameSite + * @return \Symfony\Component\HttpFoundation\Cookie + * @static + */ + public static function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->make($name, $value, $minutes, $path, $domain, $secure, $httpOnly, $raw, $sameSite); + } + + /** + * Create a cookie that lasts "forever" (400 days). + * + * @param string $name + * @param string $value + * @param string|null $path + * @param string|null $domain + * @param bool|null $secure + * @param bool $httpOnly + * @param bool $raw + * @param string|null $sameSite + * @return \Symfony\Component\HttpFoundation\Cookie + * @static + */ + public static function forever($name, $value, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->forever($name, $value, $path, $domain, $secure, $httpOnly, $raw, $sameSite); + } + + /** + * Expire the given cookie. + * + * @param string $name + * @param string|null $path + * @param string|null $domain + * @return \Symfony\Component\HttpFoundation\Cookie + * @static + */ + public static function forget($name, $path = null, $domain = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->forget($name, $path, $domain); + } + + /** + * Determine if a cookie has been queued. + * + * @param string $key + * @param string|null $path + * @return bool + * @static + */ + public static function hasQueued($key, $path = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->hasQueued($key, $path); + } + + /** + * Get a queued cookie instance. + * + * @param string $key + * @param mixed $default + * @param string|null $path + * @return \Symfony\Component\HttpFoundation\Cookie|null + * @static + */ + public static function queued($key, $default = null, $path = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->queued($key, $default, $path); + } + + /** + * Queue a cookie to send with the next response. + * + * @param mixed $parameters + * @return void + * @static + */ + public static function queue(...$parameters) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + $instance->queue(...$parameters); + } + + /** + * Queue a cookie to expire with the next response. + * + * @param string $name + * @param string|null $path + * @param string|null $domain + * @return void + * @static + */ + public static function expire($name, $path = null, $domain = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + $instance->expire($name, $path, $domain); + } + + /** + * Remove a cookie from the queue. + * + * @param string $name + * @param string|null $path + * @return void + * @static + */ + public static function unqueue($name, $path = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + $instance->unqueue($name, $path); + } + + /** + * Set the default path and domain for the jar. + * + * @param string $path + * @param string|null $domain + * @param bool|null $secure + * @param string|null $sameSite + * @return \Illuminate\Cookie\CookieJar + * @static + */ + public static function setDefaultPathAndDomain($path, $domain, $secure = false, $sameSite = null) + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->setDefaultPathAndDomain($path, $domain, $secure, $sameSite); + } + + /** + * Get the cookies which have been queued for the next request. + * + * @return \Symfony\Component\HttpFoundation\Cookie[] + * @static + */ + public static function getQueuedCookies() + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->getQueuedCookies(); + } + + /** + * Flush the cookies which have been queued for the next request. + * + * @return \Illuminate\Cookie\CookieJar + * @static + */ + public static function flushQueuedCookies() + { + /** @var \Illuminate\Cookie\CookieJar $instance */ + return $instance->flushQueuedCookies(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Cookie\CookieJar::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Cookie\CookieJar::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Cookie\CookieJar::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Cookie\CookieJar::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Encryption\Encrypter + */ + class Crypt { + /** + * Determine if the given key and cipher combination is valid. + * + * @param string $key + * @param string $cipher + * @return bool + * @static + */ + public static function supported($key, $cipher) + { + return \Illuminate\Encryption\Encrypter::supported($key, $cipher); + } + + /** + * Create a new encryption key for the given cipher. + * + * @param string $cipher + * @return string + * @static + */ + public static function generateKey($cipher) + { + return \Illuminate\Encryption\Encrypter::generateKey($cipher); + } + + /** + * Encrypt the given value. + * + * @param mixed $value + * @param bool $serialize + * @return string + * @throws \Illuminate\Contracts\Encryption\EncryptException + * @static + */ + public static function encrypt($value, $serialize = true) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->encrypt($value, $serialize); + } + + /** + * Encrypt a string without serialization. + * + * @param string $value + * @return string + * @throws \Illuminate\Contracts\Encryption\EncryptException + * @static + */ + public static function encryptString($value) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->encryptString($value); + } + + /** + * Decrypt the given value. + * + * @param string $payload + * @param bool $unserialize + * @return mixed + * @throws \Illuminate\Contracts\Encryption\DecryptException + * @static + */ + public static function decrypt($payload, $unserialize = true) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->decrypt($payload, $unserialize); + } + + /** + * Decrypt the given string without unserialization. + * + * @param string $payload + * @return string + * @throws \Illuminate\Contracts\Encryption\DecryptException + * @static + */ + public static function decryptString($payload) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->decryptString($payload); + } + + /** + * Get the encryption key that the encrypter is currently using. + * + * @return string + * @static + */ + public static function getKey() + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->getKey(); + } + + /** + * Get the current encryption key and all previous encryption keys. + * + * @return array + * @static + */ + public static function getAllKeys() + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->getAllKeys(); + } + + /** + * Get the previous encryption keys. + * + * @return array + * @static + */ + public static function getPreviousKeys() + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->getPreviousKeys(); + } + + /** + * Set the previous / legacy encryption keys that should be utilized if decryption fails. + * + * @param array $keys + * @return \Illuminate\Encryption\Encrypter + * @static + */ + public static function previousKeys($keys) + { + /** @var \Illuminate\Encryption\Encrypter $instance */ + return $instance->previousKeys($keys); + } + + } + /** + * + * + * @see https://carbon.nesbot.com/docs/ + * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php + * @method static bool canBeCreatedFromFormat(?string $date, string $format) + * @method static \Illuminate\Support\Carbon|null create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromDate($year = null, $month = null, $day = null, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createFromFormat($format, $time, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createFromIsoFormat(string $format, string $time, $timezone = null, ?string $locale = 'en', ?\Symfony\Contracts\Translation\TranslatorInterface $translator = null) + * @method static \Illuminate\Support\Carbon|null createFromLocaleFormat(string $format, string $locale, string $time, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createFromLocaleIsoFormat(string $format, string $locale, string $time, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimeString(string $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestamp(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMs(string|int|float $timestamp, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon createFromTimestampMsUTC($timestamp) + * @method static \Illuminate\Support\Carbon createFromTimestampUTC(string|int|float $timestamp) + * @method static \Illuminate\Support\Carbon createMidnightDate($year = null, $month = null, $day = null, $timezone = null) + * @method static \Illuminate\Support\Carbon|null createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $timezone = null) + * @method static \Illuminate\Support\Carbon createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $timezone = null) + * @method static void disableHumanDiffOption($humanDiffOption) + * @method static void enableHumanDiffOption($humanDiffOption) + * @method static mixed executeWithLocale(string $locale, callable $func) + * @method static \Illuminate\Support\Carbon fromSerialized($value) + * @method static array getAvailableLocales() + * @method static array getAvailableLocalesInfo() + * @method static array getDays() + * @method static ?string getFallbackLocale() + * @method static array getFormatsToIsoReplacements() + * @method static int getHumanDiffOptions() + * @method static array getIsoUnits() + * @method static array|false getLastErrors() + * @method static string getLocale() + * @method static int getMidDayAt() + * @method static string getTimeFormatByPrecision(string $unitPrecision) + * @method static string|\Closure|null getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null) + * @method static \Illuminate\Support\Carbon|null getTestNow() + * @method static \Symfony\Contracts\Translation\TranslatorInterface getTranslator() + * @method static int getWeekEndsAt(?string $locale = null) + * @method static int getWeekStartsAt(?string $locale = null) + * @method static array getWeekendDays() + * @method static bool hasFormat(string $date, string $format) + * @method static bool hasFormatWithModifiers(string $date, string $format) + * @method static bool hasMacro($name) + * @method static bool hasRelativeKeywords(?string $time) + * @method static bool hasTestNow() + * @method static \Illuminate\Support\Carbon instance(\DateTimeInterface $date) + * @method static bool isImmutable() + * @method static bool isModifiableUnit($unit) + * @method static bool isMutable() + * @method static bool isStrictModeEnabled() + * @method static bool localeHasDiffOneDayWords(string $locale) + * @method static bool localeHasDiffSyntax(string $locale) + * @method static bool localeHasDiffTwoDayWords(string $locale) + * @method static bool localeHasPeriodSyntax($locale) + * @method static bool localeHasShortUnits(string $locale) + * @method static void macro(string $name, ?callable $macro) + * @method static \Illuminate\Support\Carbon|null make($var, \DateTimeZone|string|null $timezone = null) + * @method static void mixin(object|string $mixin) + * @method static \Illuminate\Support\Carbon now(\DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parse(\DateTimeInterface|\Carbon\WeekDay|\Carbon\Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon parseFromLocale(string $time, ?string $locale = null, \DateTimeZone|string|int|null $timezone = null) + * @method static string pluralUnit(string $unit) + * @method static \Illuminate\Support\Carbon|null rawCreateFromFormat(string $format, string $time, $timezone = null) + * @method static \Illuminate\Support\Carbon rawParse(\DateTimeInterface|\Carbon\WeekDay|\Carbon\Month|string|int|float|null $time, \DateTimeZone|string|int|null $timezone = null) + * @method static void resetMonthsOverflow() + * @method static void resetToStringFormat() + * @method static void resetYearsOverflow() + * @method static void serializeUsing($callback) + * @method static void setFallbackLocale(string $locale) + * @method static void setHumanDiffOptions($humanDiffOptions) + * @method static void setLocale(string $locale) + * @method static void setMidDayAt($hour) + * @method static void setTestNow(mixed $testNow = null) + * @method static void setTestNowAndTimezone(mixed $testNow = null, $timezone = null) + * @method static void setToStringFormat(string|\Closure|null $format) + * @method static void setTranslator(\Symfony\Contracts\Translation\TranslatorInterface $translator) + * @method static void setWeekEndsAt($day) + * @method static void setWeekStartsAt($day) + * @method static void setWeekendDays($days) + * @method static bool shouldOverflowMonths() + * @method static bool shouldOverflowYears() + * @method static string singularUnit(string $unit) + * @method static void sleep(int|float $seconds) + * @method static \Illuminate\Support\Carbon today(\DateTimeZone|string|int|null $timezone = null) + * @method static \Illuminate\Support\Carbon tomorrow(\DateTimeZone|string|int|null $timezone = null) + * @method static string translateTimeString(string $timeString, ?string $from = null, ?string $to = null, int $mode = \Carbon\CarbonInterface::TRANSLATE_ALL) + * @method static string translateWith(\Symfony\Contracts\Translation\TranslatorInterface $translator, string $key, array $parameters = [], $number = null) + * @method static void useMonthsOverflow($monthsOverflow = true) + * @method static void useStrictMode($strictModeEnabled = true) + * @method static void useYearsOverflow($yearsOverflow = true) + * @method static mixed withTestNow(mixed $testNow, callable $callback) + * @method static static withTimeZone(\DateTimeZone|string|int|null $timezone) + * @method static \Illuminate\Support\Carbon yesterday(\DateTimeZone|string|int|null $timezone = null) + * @see \Illuminate\Support\DateFactory + */ + class Date { + /** + * Use the given handler when generating dates (class name, callable, or factory). + * + * @param mixed $handler + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function use($handler) + { + return \Illuminate\Support\DateFactory::use($handler); + } + + /** + * Use the default date class when generating dates. + * + * @return void + * @static + */ + public static function useDefault() + { + \Illuminate\Support\DateFactory::useDefault(); + } + + /** + * Execute the given callable on each date creation. + * + * @param callable $callable + * @return void + * @static + */ + public static function useCallable($callable) + { + \Illuminate\Support\DateFactory::useCallable($callable); + } + + /** + * Use the given date type (class) when generating dates. + * + * @param string $dateClass + * @return void + * @static + */ + public static function useClass($dateClass) + { + \Illuminate\Support\DateFactory::useClass($dateClass); + } + + /** + * Use the given Carbon factory when generating dates. + * + * @param object $factory + * @return void + * @static + */ + public static function useFactory($factory) + { + \Illuminate\Support\DateFactory::useFactory($factory); + } + + } + /** + * + * + * @see \Illuminate\Database\DatabaseManager + */ + class DB { + /** + * Get a database connection instance. + * + * @param string|null $name + * @return \Illuminate\Database\Connection + * @static + */ + public static function connection($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->connection($name); + } + + /** + * Build a database connection instance from the given configuration. + * + * @param array $config + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->build($config); + } + + /** + * Calculate the dynamic connection name for an on-demand connection based on its configuration. + * + * @param array $config + * @return string + * @static + */ + public static function calculateDynamicConnectionName($config) + { + return \Illuminate\Database\DatabaseManager::calculateDynamicConnectionName($config); + } + + /** + * Get a database connection instance from the given configuration. + * + * @param string $name + * @param array $config + * @param bool $force + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function connectUsing($name, $config, $force = false) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->connectUsing($name, $config, $force); + } + + /** + * Disconnect from the given database and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->purge($name); + } + + /** + * Disconnect from the given database. + * + * @param string|null $name + * @return void + * @static + */ + public static function disconnect($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->disconnect($name); + } + + /** + * Reconnect to the given database. + * + * @param string|null $name + * @return \Illuminate\Database\Connection + * @static + */ + public static function reconnect($name = null) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->reconnect($name); + } + + /** + * Set the default database connection for the callback execution. + * + * @param string $name + * @param callable $callback + * @return mixed + * @static + */ + public static function usingConnection($name, $callback) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->usingConnection($name, $callback); + } + + /** + * Get the default connection name. + * + * @return string + * @static + */ + public static function getDefaultConnection() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->getDefaultConnection(); + } + + /** + * Set the default connection name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultConnection($name) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->setDefaultConnection($name); + } + + /** + * Get all of the supported drivers. + * + * @return string[] + * @static + */ + public static function supportedDrivers() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->supportedDrivers(); + } + + /** + * Get all of the drivers that are actually available. + * + * @return string[] + * @static + */ + public static function availableDrivers() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->availableDrivers(); + } + + /** + * Register an extension connection resolver. + * + * @param string $name + * @param callable $resolver + * @return void + * @static + */ + public static function extend($name, $resolver) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->extend($name, $resolver); + } + + /** + * Remove an extension connection resolver. + * + * @param string $name + * @return void + * @static + */ + public static function forgetExtension($name) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->forgetExtension($name); + } + + /** + * Return all of the created connections. + * + * @return array + * @static + */ + public static function getConnections() + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->getConnections(); + } + + /** + * Set the database reconnector callback. + * + * @param callable $reconnector + * @return void + * @static + */ + public static function setReconnector($reconnector) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + $instance->setReconnector($reconnector); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Database\DatabaseManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->setApplication($app); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Database\DatabaseManager::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Database\DatabaseManager::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Database\DatabaseManager::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Database\DatabaseManager::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Database\DatabaseManager $instance */ + return $instance->macroCall($method, $parameters); + } + + /** + * Get a human-readable name for the given connection driver. + * + * @return string + * @static + */ + public static function getDriverTitle() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getDriverTitle(); + } + + /** + * Run an insert statement against the database. + * + * @param string $query + * @param array $bindings + * @param string|null $sequence + * @return bool + * @static + */ + public static function insert($query, $bindings = [], $sequence = null) + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->insert($query, $bindings, $sequence); + } + + /** + * Get the connection's last insert ID. + * + * @return string|int|null + * @static + */ + public static function getLastInsertId() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getLastInsertId(); + } + + /** + * Determine if the connected database is a MariaDB database. + * + * @return bool + * @static + */ + public static function isMaria() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->isMaria(); + } + + /** + * Get the server version for the connection. + * + * @return string + * @static + */ + public static function getServerVersion() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getServerVersion(); + } + + /** + * Get a schema builder instance for the connection. + * + * @return \Illuminate\Database\Schema\MySqlBuilder + * @static + */ + public static function getSchemaBuilder() + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getSchemaBuilder(); + } + + /** + * Get the schema state for the connection. + * + * @param \Illuminate\Filesystem\Filesystem|null $files + * @param callable|null $processFactory + * @return \Illuminate\Database\Schema\MySqlSchemaState + * @static + */ + public static function getSchemaState($files = null, $processFactory = null) + { + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getSchemaState($files, $processFactory); + } + + /** + * Set the query grammar to the default implementation. + * + * @return void + * @static + */ + public static function useDefaultQueryGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->useDefaultQueryGrammar(); + } + + /** + * Set the schema grammar to the default implementation. + * + * @return void + * @static + */ + public static function useDefaultSchemaGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->useDefaultSchemaGrammar(); + } + + /** + * Set the query post processor to the default implementation. + * + * @return void + * @static + */ + public static function useDefaultPostProcessor() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->useDefaultPostProcessor(); + } + + /** + * Begin a fluent query against a database table. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Contracts\Database\Query\Expression|string $table + * @param string|null $as + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function table($table, $as = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->table($table, $as); + } + + /** + * Get a new query builder instance. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function query() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->query(); + } + + /** + * Run a select statement and return a single result. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return mixed + * @static + */ + public static function selectOne($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->selectOne($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement and return the first column of the first row. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return mixed + * @throws \Illuminate\Database\MultipleColumnsSelectedException + * @static + */ + public static function scalar($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->scalar($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement against the database. + * + * @param string $query + * @param array $bindings + * @return array + * @static + */ + public static function selectFromWriteConnection($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->selectFromWriteConnection($query, $bindings); + } + + /** + * Run a select statement against the database. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return array + * @static + */ + public static function select($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->select($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement against the database and returns all of the result sets. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return array + * @static + */ + public static function selectResultSets($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->selectResultSets($query, $bindings, $useReadPdo); + } + + /** + * Run a select statement against the database and returns a generator. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return \Generator + * @static + */ + public static function cursor($query, $bindings = [], $useReadPdo = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->cursor($query, $bindings, $useReadPdo); + } + + /** + * Run an update statement against the database. + * + * @param string $query + * @param array $bindings + * @return int + * @static + */ + public static function update($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->update($query, $bindings); + } + + /** + * Run a delete statement against the database. + * + * @param string $query + * @param array $bindings + * @return int + * @static + */ + public static function delete($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->delete($query, $bindings); + } + + /** + * Execute an SQL statement and return the boolean result. + * + * @param string $query + * @param array $bindings + * @return bool + * @static + */ + public static function statement($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->statement($query, $bindings); + } + + /** + * Run an SQL statement and get the number of rows affected. + * + * @param string $query + * @param array $bindings + * @return int + * @static + */ + public static function affectingStatement($query, $bindings = []) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->affectingStatement($query, $bindings); + } + + /** + * Run a raw, unprepared query against the PDO connection. + * + * @param string $query + * @return bool + * @static + */ + public static function unprepared($query) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->unprepared($query); + } + + /** + * Get the number of open connections for the database. + * + * @return int|null + * @static + */ + public static function threadCount() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->threadCount(); + } + + /** + * Execute the given callback in "dry run" mode. + * + * @param \Closure $callback + * @return array + * @static + */ + public static function pretend($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->pretend($callback); + } + + /** + * Execute the given callback without "pretending". + * + * @param \Closure $callback + * @return mixed + * @static + */ + public static function withoutPretending($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->withoutPretending($callback); + } + + /** + * Bind values to their parameters in the given statement. + * + * @param \PDOStatement $statement + * @param array $bindings + * @return void + * @static + */ + public static function bindValues($statement, $bindings) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->bindValues($statement, $bindings); + } + + /** + * Prepare the query bindings for execution. + * + * @param array $bindings + * @return array + * @static + */ + public static function prepareBindings($bindings) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->prepareBindings($bindings); + } + + /** + * Log a query in the connection's query log. + * + * @param string $query + * @param array $bindings + * @param float|null $time + * @return void + * @static + */ + public static function logQuery($query, $bindings, $time = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->logQuery($query, $bindings, $time); + } + + /** + * Register a callback to be invoked when the connection queries for longer than a given amount of time. + * + * @param \DateTimeInterface|\Carbon\CarbonInterval|float|int $threshold + * @param callable $handler + * @return void + * @static + */ + public static function whenQueryingForLongerThan($threshold, $handler) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->whenQueryingForLongerThan($threshold, $handler); + } + + /** + * Allow all the query duration handlers to run again, even if they have already run. + * + * @return void + * @static + */ + public static function allowQueryDurationHandlersToRunAgain() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->allowQueryDurationHandlersToRunAgain(); + } + + /** + * Get the duration of all run queries in milliseconds. + * + * @return float + * @static + */ + public static function totalQueryDuration() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->totalQueryDuration(); + } + + /** + * Reset the duration of all run queries. + * + * @return void + * @static + */ + public static function resetTotalQueryDuration() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->resetTotalQueryDuration(); + } + + /** + * Reconnect to the database if a PDO connection is missing. + * + * @return void + * @static + */ + public static function reconnectIfMissingConnection() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->reconnectIfMissingConnection(); + } + + /** + * Register a hook to be run just before a database transaction is started. + * + * @param \Closure $callback + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function beforeStartingTransaction($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->beforeStartingTransaction($callback); + } + + /** + * Register a hook to be run just before a database query is executed. + * + * @param \Closure $callback + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function beforeExecuting($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->beforeExecuting($callback); + } + + /** + * Register a database query listener with the connection. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function listen($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->listen($callback); + } + + /** + * Get a new raw query expression. + * + * @param mixed $value + * @return \Illuminate\Contracts\Database\Query\Expression + * @static + */ + public static function raw($value) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->raw($value); + } + + /** + * Escape a value for safe SQL embedding. + * + * @param string|float|int|bool|null $value + * @param bool $binary + * @return string + * @static + */ + public static function escape($value, $binary = false) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->escape($value, $binary); + } + + /** + * Determine if the database connection has modified any database records. + * + * @return bool + * @static + */ + public static function hasModifiedRecords() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->hasModifiedRecords(); + } + + /** + * Indicate if any records have been modified. + * + * @param bool $value + * @return void + * @static + */ + public static function recordsHaveBeenModified($value = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->recordsHaveBeenModified($value); + } + + /** + * Set the record modification state. + * + * @param bool $value + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setRecordModificationState($value) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setRecordModificationState($value); + } + + /** + * Reset the record modification state. + * + * @return void + * @static + */ + public static function forgetRecordModificationState() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->forgetRecordModificationState(); + } + + /** + * Indicate that the connection should use the write PDO connection for reads. + * + * @param bool $value + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function useWriteConnectionWhenReading($value = true) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->useWriteConnectionWhenReading($value); + } + + /** + * Get the current PDO connection. + * + * @return \PDO + * @static + */ + public static function getPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getPdo(); + } + + /** + * Get the current PDO connection parameter without executing any reconnect logic. + * + * @return \PDO|\Closure|null + * @static + */ + public static function getRawPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getRawPdo(); + } + + /** + * Get the current PDO connection used for reading. + * + * @return \PDO + * @static + */ + public static function getReadPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getReadPdo(); + } + + /** + * Get the current read PDO connection parameter without executing any reconnect logic. + * + * @return \PDO|\Closure|null + * @static + */ + public static function getRawReadPdo() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getRawReadPdo(); + } + + /** + * Set the PDO connection. + * + * @param \PDO|\Closure|null $pdo + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setPdo($pdo) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setPdo($pdo); + } + + /** + * Set the PDO connection used for reading. + * + * @param \PDO|\Closure|null $pdo + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setReadPdo($pdo) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setReadPdo($pdo); + } + + /** + * Get the database connection name. + * + * @return string|null + * @static + */ + public static function getName() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getName(); + } + + /** + * Get the database connection full name. + * + * @return string|null + * @static + */ + public static function getNameWithReadWriteType() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getNameWithReadWriteType(); + } + + /** + * Get an option from the configuration options. + * + * @param string|null $option + * @return mixed + * @static + */ + public static function getConfig($option = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getConfig($option); + } + + /** + * Get the PDO driver name. + * + * @return string + * @static + */ + public static function getDriverName() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getDriverName(); + } + + /** + * Get the query grammar used by the connection. + * + * @return \Illuminate\Database\Query\Grammars\Grammar + * @static + */ + public static function getQueryGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getQueryGrammar(); + } + + /** + * Set the query grammar used by the connection. + * + * @param \Illuminate\Database\Query\Grammars\Grammar $grammar + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setQueryGrammar($grammar) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setQueryGrammar($grammar); + } + + /** + * Get the schema grammar used by the connection. + * + * @return \Illuminate\Database\Schema\Grammars\Grammar + * @static + */ + public static function getSchemaGrammar() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getSchemaGrammar(); + } + + /** + * Set the schema grammar used by the connection. + * + * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setSchemaGrammar($grammar) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setSchemaGrammar($grammar); + } + + /** + * Get the query post processor used by the connection. + * + * @return \Illuminate\Database\Query\Processors\Processor + * @static + */ + public static function getPostProcessor() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getPostProcessor(); + } + + /** + * Set the query post processor used by the connection. + * + * @param \Illuminate\Database\Query\Processors\Processor $processor + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setPostProcessor($processor) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setPostProcessor($processor); + } + + /** + * Get the event dispatcher used by the connection. + * + * @return \Illuminate\Contracts\Events\Dispatcher + * @static + */ + public static function getEventDispatcher() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getEventDispatcher(); + } + + /** + * Set the event dispatcher instance on the connection. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setEventDispatcher($events) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setEventDispatcher($events); + } + + /** + * Unset the event dispatcher for this connection. + * + * @return void + * @static + */ + public static function unsetEventDispatcher() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->unsetEventDispatcher(); + } + + /** + * Set the transaction manager instance on the connection. + * + * @param \Illuminate\Database\DatabaseTransactionsManager $manager + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setTransactionManager($manager) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setTransactionManager($manager); + } + + /** + * Unset the transaction manager for this connection. + * + * @return void + * @static + */ + public static function unsetTransactionManager() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->unsetTransactionManager(); + } + + /** + * Determine if the connection is in a "dry run". + * + * @return bool + * @static + */ + public static function pretending() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->pretending(); + } + + /** + * Get the connection query log. + * + * @return array + * @static + */ + public static function getQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getQueryLog(); + } + + /** + * Get the connection query log with embedded bindings. + * + * @return array + * @static + */ + public static function getRawQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getRawQueryLog(); + } + + /** + * Clear the query log. + * + * @return void + * @static + */ + public static function flushQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->flushQueryLog(); + } + + /** + * Enable the query log on the connection. + * + * @return void + * @static + */ + public static function enableQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->enableQueryLog(); + } + + /** + * Disable the query log on the connection. + * + * @return void + * @static + */ + public static function disableQueryLog() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->disableQueryLog(); + } + + /** + * Determine whether we're logging queries. + * + * @return bool + * @static + */ + public static function logging() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->logging(); + } + + /** + * Get the name of the connected database. + * + * @return string + * @static + */ + public static function getDatabaseName() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getDatabaseName(); + } + + /** + * Set the name of the connected database. + * + * @param string $database + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setDatabaseName($database) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setDatabaseName($database); + } + + /** + * Set the read / write type of the connection. + * + * @param string|null $readWriteType + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setReadWriteType($readWriteType) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setReadWriteType($readWriteType); + } + + /** + * Get the table prefix for the connection. + * + * @return string + * @static + */ + public static function getTablePrefix() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->getTablePrefix(); + } + + /** + * Set the table prefix in use by the connection. + * + * @param string $prefix + * @return \Illuminate\Database\MySqlConnection + * @static + */ + public static function setTablePrefix($prefix) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->setTablePrefix($prefix); + } + + /** + * Execute the given callback without table prefix. + * + * @param \Closure $callback + * @return mixed + * @static + */ + public static function withoutTablePrefix($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->withoutTablePrefix($callback); + } + + /** + * Register a connection resolver. + * + * @param string $driver + * @param \Closure $callback + * @return void + * @static + */ + public static function resolverFor($driver, $callback) + { + //Method inherited from \Illuminate\Database\Connection + \Illuminate\Database\MySqlConnection::resolverFor($driver, $callback); + } + + /** + * Get the connection resolver for the given driver. + * + * @param string $driver + * @return \Closure|null + * @static + */ + public static function getResolver($driver) + { + //Method inherited from \Illuminate\Database\Connection + return \Illuminate\Database\MySqlConnection::getResolver($driver); + } + + /** + * + * + * @template TReturn of mixed + * + * Execute a Closure within a transaction. + * @param (\Closure(static): TReturn) $callback + * @param int $attempts + * @return TReturn + * @throws \Throwable + * @static + */ + public static function transaction($callback, $attempts = 1) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->transaction($callback, $attempts); + } + + /** + * Start a new database transaction. + * + * @return void + * @throws \Throwable + * @static + */ + public static function beginTransaction() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->beginTransaction(); + } + + /** + * Commit the active database transaction. + * + * @return void + * @throws \Throwable + * @static + */ + public static function commit() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->commit(); + } + + /** + * Rollback the active database transaction. + * + * @param int|null $toLevel + * @return void + * @throws \Throwable + * @static + */ + public static function rollBack($toLevel = null) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->rollBack($toLevel); + } + + /** + * Get the number of active transactions. + * + * @return int + * @static + */ + public static function transactionLevel() + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + return $instance->transactionLevel(); + } + + /** + * Execute the callback after a transaction commits. + * + * @param callable $callback + * @return void + * @throws \RuntimeException + * @static + */ + public static function afterCommit($callback) + { + //Method inherited from \Illuminate\Database\Connection + /** @var \Illuminate\Database\MySqlConnection $instance */ + $instance->afterCommit($callback); + } + + } + /** + * + * + * @see \Illuminate\Events\Dispatcher + * @see \Illuminate\Support\Testing\Fakes\EventFake + */ + class Event { + /** + * Register an event listener with the dispatcher. + * + * @param \Illuminate\Events\Queued\Closure|callable|array|class-string|string $events + * @param \Illuminate\Events\Queued\Closure|callable|array|class-string|null $listener + * @return void + * @static + */ + public static function listen($events, $listener = null) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->listen($events, $listener); + } + + /** + * Determine if a given event has listeners. + * + * @param string $eventName + * @return bool + * @static + */ + public static function hasListeners($eventName) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->hasListeners($eventName); + } + + /** + * Determine if the given event has any wildcard listeners. + * + * @param string $eventName + * @return bool + * @static + */ + public static function hasWildcardListeners($eventName) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->hasWildcardListeners($eventName); + } + + /** + * Register an event and payload to be fired later. + * + * @param string $event + * @param object|array $payload + * @return void + * @static + */ + public static function push($event, $payload = []) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->push($event, $payload); + } + + /** + * Flush a set of pushed events. + * + * @param string $event + * @return void + * @static + */ + public static function flush($event) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->flush($event); + } + + /** + * Register an event subscriber with the dispatcher. + * + * @param object|string $subscriber + * @return void + * @static + */ + public static function subscribe($subscriber) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->subscribe($subscriber); + } + + /** + * Fire an event until the first non-null response is returned. + * + * @param string|object $event + * @param mixed $payload + * @return mixed + * @static + */ + public static function until($event, $payload = []) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->until($event, $payload); + } + + /** + * Fire an event and call the listeners. + * + * @param string|object $event + * @param mixed $payload + * @param bool $halt + * @return array|null + * @static + */ + public static function dispatch($event, $payload = [], $halt = false) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->dispatch($event, $payload, $halt); + } + + /** + * Get all of the listeners for a given event name. + * + * @param string $eventName + * @return array + * @static + */ + public static function getListeners($eventName) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->getListeners($eventName); + } + + /** + * Register an event listener with the dispatcher. + * + * @param \Closure|string|array $listener + * @param bool $wildcard + * @return \Closure + * @static + */ + public static function makeListener($listener, $wildcard = false) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->makeListener($listener, $wildcard); + } + + /** + * Create a class based listener using the IoC container. + * + * @param string $listener + * @param bool $wildcard + * @return \Closure + * @static + */ + public static function createClassListener($listener, $wildcard = false) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->createClassListener($listener, $wildcard); + } + + /** + * Remove a set of listeners from the dispatcher. + * + * @param string $event + * @return void + * @static + */ + public static function forget($event) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->forget($event); + } + + /** + * Forget all of the pushed listeners. + * + * @return void + * @static + */ + public static function forgetPushed() + { + /** @var \Illuminate\Events\Dispatcher $instance */ + $instance->forgetPushed(); + } + + /** + * Set the queue resolver implementation. + * + * @param callable $resolver + * @return \Illuminate\Events\Dispatcher + * @static + */ + public static function setQueueResolver($resolver) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->setQueueResolver($resolver); + } + + /** + * Set the database transaction manager resolver implementation. + * + * @param callable $resolver + * @return \Illuminate\Events\Dispatcher + * @static + */ + public static function setTransactionManagerResolver($resolver) + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->setTransactionManagerResolver($resolver); + } + + /** + * Gets the raw, unprepared listeners. + * + * @return array + * @static + */ + public static function getRawListeners() + { + /** @var \Illuminate\Events\Dispatcher $instance */ + return $instance->getRawListeners(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Events\Dispatcher::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Events\Dispatcher::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Events\Dispatcher::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Events\Dispatcher::flushMacros(); + } + + /** + * Specify the events that should be dispatched instead of faked. + * + * @param array|string $eventsToDispatch + * @return \Illuminate\Support\Testing\Fakes\EventFake + * @static + */ + public static function except($eventsToDispatch) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->except($eventsToDispatch); + } + + /** + * Assert if an event has a listener attached to it. + * + * @param string $expectedEvent + * @param string|array $expectedListener + * @return void + * @static + */ + public static function assertListening($expectedEvent, $expectedListener) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertListening($expectedEvent, $expectedListener); + } + + /** + * Assert if an event was dispatched based on a truth-test callback. + * + * @param string|\Closure $event + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertDispatched($event, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertDispatched($event, $callback); + } + + /** + * Assert if an event was dispatched a number of times. + * + * @param string $event + * @param int $times + * @return void + * @static + */ + public static function assertDispatchedTimes($event, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertDispatchedTimes($event, $times); + } + + /** + * Determine if an event was dispatched based on a truth-test callback. + * + * @param string|\Closure $event + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotDispatched($event, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertNotDispatched($event, $callback); + } + + /** + * Assert that no events were dispatched. + * + * @return void + * @static + */ + public static function assertNothingDispatched() + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + $instance->assertNothingDispatched(); + } + + /** + * Get all of the events matching a truth-test callback. + * + * @param string $event + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function dispatched($event, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->dispatched($event, $callback); + } + + /** + * Determine if the given event has been dispatched. + * + * @param string $event + * @return bool + * @static + */ + public static function hasDispatched($event) + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->hasDispatched($event); + } + + /** + * Get the events that have been dispatched. + * + * @return array + * @static + */ + public static function dispatchedEvents() + { + /** @var \Illuminate\Support\Testing\Fakes\EventFake $instance */ + return $instance->dispatchedEvents(); + } + + } + /** + * + * + * @see \Illuminate\Filesystem\Filesystem + */ + class File { + /** + * Determine if a file or directory exists. + * + * @param string $path + * @return bool + * @static + */ + public static function exists($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->exists($path); + } + + /** + * Determine if a file or directory is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function missing($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->missing($path); + } + + /** + * Get the contents of a file. + * + * @param string $path + * @param bool $lock + * @return string + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function get($path, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->get($path, $lock); + } + + /** + * Get the contents of a file as decoded JSON. + * + * @param string $path + * @param int $flags + * @param bool $lock + * @return array + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function json($path, $flags = 0, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->json($path, $flags, $lock); + } + + /** + * Get contents of a file with shared access. + * + * @param string $path + * @return string + * @static + */ + public static function sharedGet($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->sharedGet($path); + } + + /** + * Get the returned value of a file. + * + * @param string $path + * @param array $data + * @return mixed + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function getRequire($path, $data = []) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->getRequire($path, $data); + } + + /** + * Require the given file once. + * + * @param string $path + * @param array $data + * @return mixed + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function requireOnce($path, $data = []) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->requireOnce($path, $data); + } + + /** + * Get the contents of a file one line at a time. + * + * @param string $path + * @return \Illuminate\Support\LazyCollection + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @static + */ + public static function lines($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->lines($path); + } + + /** + * Get the hash of the file at the given path. + * + * @param string $path + * @param string $algorithm + * @return string|false + * @static + */ + public static function hash($path, $algorithm = 'md5') + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->hash($path, $algorithm); + } + + /** + * Write the contents of a file. + * + * @param string $path + * @param string $contents + * @param bool $lock + * @return int|bool + * @static + */ + public static function put($path, $contents, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->put($path, $contents, $lock); + } + + /** + * Write the contents of a file, replacing it atomically if it already exists. + * + * @param string $path + * @param string $content + * @param int|null $mode + * @return void + * @static + */ + public static function replace($path, $content, $mode = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->replace($path, $content, $mode); + } + + /** + * Replace a given string within a given file. + * + * @param array|string $search + * @param array|string $replace + * @param string $path + * @return void + * @static + */ + public static function replaceInFile($search, $replace, $path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->replaceInFile($search, $replace, $path); + } + + /** + * Prepend to a file. + * + * @param string $path + * @param string $data + * @return int + * @static + */ + public static function prepend($path, $data) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->prepend($path, $data); + } + + /** + * Append to a file. + * + * @param string $path + * @param string $data + * @param bool $lock + * @return int + * @static + */ + public static function append($path, $data, $lock = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->append($path, $data, $lock); + } + + /** + * Get or set UNIX mode of a file or directory. + * + * @param string $path + * @param int|null $mode + * @return mixed + * @static + */ + public static function chmod($path, $mode = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->chmod($path, $mode); + } + + /** + * Delete the file at a given path. + * + * @param string|array $paths + * @return bool + * @static + */ + public static function delete($paths) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->delete($paths); + } + + /** + * Move a file to a new location. + * + * @param string $path + * @param string $target + * @return bool + * @static + */ + public static function move($path, $target) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->move($path, $target); + } + + /** + * Copy a file to a new location. + * + * @param string $path + * @param string $target + * @return bool + * @static + */ + public static function copy($path, $target) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->copy($path, $target); + } + + /** + * Create a symlink to the target file or directory. On Windows, a hard link is created if the target is a file. + * + * @param string $target + * @param string $link + * @return bool|null + * @static + */ + public static function link($target, $link) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->link($target, $link); + } + + /** + * Create a relative symlink to the target file or directory. + * + * @param string $target + * @param string $link + * @return void + * @throws \RuntimeException + * @static + */ + public static function relativeLink($target, $link) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->relativeLink($target, $link); + } + + /** + * Extract the file name from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function name($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->name($path); + } + + /** + * Extract the trailing name component from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function basename($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->basename($path); + } + + /** + * Extract the parent directory from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function dirname($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->dirname($path); + } + + /** + * Extract the file extension from a file path. + * + * @param string $path + * @return string + * @static + */ + public static function extension($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->extension($path); + } + + /** + * Guess the file extension from the mime-type of a given file. + * + * @param string $path + * @return string|null + * @throws \RuntimeException + * @static + */ + public static function guessExtension($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->guessExtension($path); + } + + /** + * Get the file type of a given file. + * + * @param string $path + * @return string + * @static + */ + public static function type($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->type($path); + } + + /** + * Get the mime-type of a given file. + * + * @param string $path + * @return string|false + * @static + */ + public static function mimeType($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->mimeType($path); + } + + /** + * Get the file size of a given file. + * + * @param string $path + * @return int + * @static + */ + public static function size($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->size($path); + } + + /** + * Get the file's last modification time. + * + * @param string $path + * @return int + * @static + */ + public static function lastModified($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->lastModified($path); + } + + /** + * Determine if the given path is a directory. + * + * @param string $directory + * @return bool + * @static + */ + public static function isDirectory($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isDirectory($directory); + } + + /** + * Determine if the given path is a directory that does not contain any other files or directories. + * + * @param string $directory + * @param bool $ignoreDotFiles + * @return bool + * @static + */ + public static function isEmptyDirectory($directory, $ignoreDotFiles = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isEmptyDirectory($directory, $ignoreDotFiles); + } + + /** + * Determine if the given path is readable. + * + * @param string $path + * @return bool + * @static + */ + public static function isReadable($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isReadable($path); + } + + /** + * Determine if the given path is writable. + * + * @param string $path + * @return bool + * @static + */ + public static function isWritable($path) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isWritable($path); + } + + /** + * Determine if two files are the same by comparing their hashes. + * + * @param string $firstFile + * @param string $secondFile + * @return bool + * @static + */ + public static function hasSameHash($firstFile, $secondFile) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->hasSameHash($firstFile, $secondFile); + } + + /** + * Determine if the given path is a file. + * + * @param string $file + * @return bool + * @static + */ + public static function isFile($file) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->isFile($file); + } + + /** + * Find path names matching a given pattern. + * + * @param string $pattern + * @param int $flags + * @return array + * @static + */ + public static function glob($pattern, $flags = 0) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->glob($pattern, $flags); + } + + /** + * Get an array of all files in a directory. + * + * @param string $directory + * @param bool $hidden + * @return \Symfony\Component\Finder\SplFileInfo[] + * @static + */ + public static function files($directory, $hidden = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->files($directory, $hidden); + } + + /** + * Get all of the files from the given directory (recursive). + * + * @param string $directory + * @param bool $hidden + * @return \Symfony\Component\Finder\SplFileInfo[] + * @static + */ + public static function allFiles($directory, $hidden = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->allFiles($directory, $hidden); + } + + /** + * Get all of the directories within a given directory. + * + * @param string $directory + * @return array + * @static + */ + public static function directories($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->directories($directory); + } + + /** + * Ensure a directory exists. + * + * @param string $path + * @param int $mode + * @param bool $recursive + * @return void + * @static + */ + public static function ensureDirectoryExists($path, $mode = 493, $recursive = true) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + $instance->ensureDirectoryExists($path, $mode, $recursive); + } + + /** + * Create a directory. + * + * @param string $path + * @param int $mode + * @param bool $recursive + * @param bool $force + * @return bool + * @static + */ + public static function makeDirectory($path, $mode = 493, $recursive = false, $force = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->makeDirectory($path, $mode, $recursive, $force); + } + + /** + * Move a directory. + * + * @param string $from + * @param string $to + * @param bool $overwrite + * @return bool + * @static + */ + public static function moveDirectory($from, $to, $overwrite = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->moveDirectory($from, $to, $overwrite); + } + + /** + * Copy a directory from one location to another. + * + * @param string $directory + * @param string $destination + * @param int|null $options + * @return bool + * @static + */ + public static function copyDirectory($directory, $destination, $options = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->copyDirectory($directory, $destination, $options); + } + + /** + * Recursively delete a directory. + * + * The directory itself may be optionally preserved. + * + * @param string $directory + * @param bool $preserve + * @return bool + * @static + */ + public static function deleteDirectory($directory, $preserve = false) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->deleteDirectory($directory, $preserve); + } + + /** + * Remove all of the directories within a given directory. + * + * @param string $directory + * @return bool + * @static + */ + public static function deleteDirectories($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->deleteDirectories($directory); + } + + /** + * Empty the specified directory of all files and folders. + * + * @param string $directory + * @return bool + * @static + */ + public static function cleanDirectory($directory) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->cleanDirectory($directory); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\Filesystem $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Filesystem\Filesystem::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Filesystem\Filesystem::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Filesystem\Filesystem::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Filesystem\Filesystem::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Auth\Access\Gate + */ + class Gate { + /** + * Determine if a given ability has been defined. + * + * @param string|array $ability + * @return bool + * @static + */ + public static function has($ability) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->has($ability); + } + + /** + * Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is false. + * + * @param \Illuminate\Auth\Access\Response|\Closure|bool $condition + * @param string|null $message + * @param string|null $code + * @return \Illuminate\Auth\Access\Response + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function allowIf($condition, $message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->allowIf($condition, $message, $code); + } + + /** + * Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is true. + * + * @param \Illuminate\Auth\Access\Response|\Closure|bool $condition + * @param string|null $message + * @param string|null $code + * @return \Illuminate\Auth\Access\Response + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function denyIf($condition, $message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denyIf($condition, $message, $code); + } + + /** + * Define a new ability. + * + * @param \UnitEnum|string $ability + * @param callable|array|string $callback + * @return \Illuminate\Auth\Access\Gate + * @throws \InvalidArgumentException + * @static + */ + public static function define($ability, $callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->define($ability, $callback); + } + + /** + * Define abilities for a resource. + * + * @param string $name + * @param string $class + * @param array|null $abilities + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function resource($name, $class, $abilities = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->resource($name, $class, $abilities); + } + + /** + * Define a policy class for a given class type. + * + * @param string $class + * @param string $policy + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function policy($class, $policy) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->policy($class, $policy); + } + + /** + * Register a callback to run before all Gate checks. + * + * @param callable $callback + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function before($callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->before($callback); + } + + /** + * Register a callback to run after all Gate checks. + * + * @param callable $callback + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function after($callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->after($callback); + } + + /** + * Determine if all of the given abilities should be granted for the current user. + * + * @param iterable|\UnitEnum|string $ability + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function allows($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->allows($ability, $arguments); + } + + /** + * Determine if any of the given abilities should be denied for the current user. + * + * @param iterable|\UnitEnum|string $ability + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function denies($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denies($ability, $arguments); + } + + /** + * Determine if all of the given abilities should be granted for the current user. + * + * @param iterable|\UnitEnum|string $abilities + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function check($abilities, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->check($abilities, $arguments); + } + + /** + * Determine if any one of the given abilities should be granted for the current user. + * + * @param iterable|\UnitEnum|string $abilities + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function any($abilities, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->any($abilities, $arguments); + } + + /** + * Determine if all of the given abilities should be denied for the current user. + * + * @param iterable|\UnitEnum|string $abilities + * @param array|mixed $arguments + * @return bool + * @static + */ + public static function none($abilities, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->none($abilities, $arguments); + } + + /** + * Determine if the given ability should be granted for the current user. + * + * @param \UnitEnum|string $ability + * @param array|mixed $arguments + * @return \Illuminate\Auth\Access\Response + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function authorize($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->authorize($ability, $arguments); + } + + /** + * Inspect the user for the given ability. + * + * @param \UnitEnum|string $ability + * @param array|mixed $arguments + * @return \Illuminate\Auth\Access\Response + * @static + */ + public static function inspect($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->inspect($ability, $arguments); + } + + /** + * Get the raw result from the authorization callback. + * + * @param string $ability + * @param array|mixed $arguments + * @return mixed + * @throws \Illuminate\Auth\Access\AuthorizationException + * @static + */ + public static function raw($ability, $arguments = []) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->raw($ability, $arguments); + } + + /** + * Get a policy instance for a given class. + * + * @param object|string $class + * @return mixed + * @static + */ + public static function getPolicyFor($class) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->getPolicyFor($class); + } + + /** + * Specify a callback to be used to guess policy names. + * + * @param callable $callback + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function guessPolicyNamesUsing($callback) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->guessPolicyNamesUsing($callback); + } + + /** + * Build a policy class instance of the given type. + * + * @param object|string $class + * @return mixed + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @static + */ + public static function resolvePolicy($class) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->resolvePolicy($class); + } + + /** + * Get a gate instance for the given user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable|mixed $user + * @return static + * @static + */ + public static function forUser($user) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->forUser($user); + } + + /** + * Get all of the defined abilities. + * + * @return array + * @static + */ + public static function abilities() + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->abilities(); + } + + /** + * Get all of the defined policies. + * + * @return array + * @static + */ + public static function policies() + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->policies(); + } + + /** + * Set the default denial response for gates and policies. + * + * @param \Illuminate\Auth\Access\Response $response + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function defaultDenialResponse($response) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->defaultDenialResponse($response); + } + + /** + * Set the container instance used by the gate. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Auth\Access\Gate + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->setContainer($container); + } + + /** + * Deny with a HTTP status code. + * + * @param int $status + * @param string|null $message + * @param int|null $code + * @return \Illuminate\Auth\Access\Response + * @static + */ + public static function denyWithStatus($status, $message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denyWithStatus($status, $message, $code); + } + + /** + * Deny with a 404 HTTP status code. + * + * @param string|null $message + * @param int|null $code + * @return \Illuminate\Auth\Access\Response + * @static + */ + public static function denyAsNotFound($message = null, $code = null) + { + /** @var \Illuminate\Auth\Access\Gate $instance */ + return $instance->denyAsNotFound($message, $code); + } + + } + /** + * + * + * @see \Illuminate\Hashing\HashManager + * @see \Illuminate\Hashing\AbstractHasher + */ + class Hash { + /** + * Create an instance of the Bcrypt hash Driver. + * + * @return \Illuminate\Hashing\BcryptHasher + * @static + */ + public static function createBcryptDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->createBcryptDriver(); + } + + /** + * Create an instance of the Argon2i hash Driver. + * + * @return \Illuminate\Hashing\ArgonHasher + * @static + */ + public static function createArgonDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->createArgonDriver(); + } + + /** + * Create an instance of the Argon2id hash Driver. + * + * @return \Illuminate\Hashing\Argon2IdHasher + * @static + */ + public static function createArgon2idDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->createArgon2idDriver(); + } + + /** + * Get information about the given hashed value. + * + * @param string $hashedValue + * @return array + * @static + */ + public static function info($hashedValue) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->info($hashedValue); + } + + /** + * Hash the given value. + * + * @param string $value + * @param array $options + * @return string + * @static + */ + public static function make($value, $options = []) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->make($value, $options); + } + + /** + * Check the given plain value against a hash. + * + * @param string $value + * @param string $hashedValue + * @param array $options + * @return bool + * @static + */ + public static function check($value, $hashedValue, $options = []) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->check($value, $hashedValue, $options); + } + + /** + * Check if the given hash has been hashed using the given options. + * + * @param string $hashedValue + * @param array $options + * @return bool + * @static + */ + public static function needsRehash($hashedValue, $options = []) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->needsRehash($hashedValue, $options); + } + + /** + * Determine if a given string is already hashed. + * + * @param string $value + * @return bool + * @static + */ + public static function isHashed($value) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->isHashed($value); + } + + /** + * Get the default driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Verifies that the configuration is less than or equal to what is configured. + * + * @param array $value + * @return bool + * @internal + * @static + */ + public static function verifyConfiguration($value) + { + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->verifyConfiguration($value); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function driver($driver = null) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->driver($driver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Hashing\HashManager + * @static + */ + public static function extend($driver, $callback) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get all of the created "drivers". + * + * @return array + * @static + */ + public static function getDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->getDrivers(); + } + + /** + * Get the container instance used by the manager. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the manager. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Hashing\HashManager + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->setContainer($container); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Hashing\HashManager + * @static + */ + public static function forgetDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Hashing\HashManager $instance */ + return $instance->forgetDrivers(); + } + + } + /** + * + * + * @method static \Illuminate\Http\Client\PendingRequest baseUrl(string $url) + * @method static \Illuminate\Http\Client\PendingRequest withBody(\Psr\Http\Message\StreamInterface|string $content, string $contentType = 'application/json') + * @method static \Illuminate\Http\Client\PendingRequest asJson() + * @method static \Illuminate\Http\Client\PendingRequest asForm() + * @method static \Illuminate\Http\Client\PendingRequest attach(string|array $name, string|resource $contents = '', string|null $filename = null, array $headers = []) + * @method static \Illuminate\Http\Client\PendingRequest asMultipart() + * @method static \Illuminate\Http\Client\PendingRequest bodyFormat(string $format) + * @method static \Illuminate\Http\Client\PendingRequest withQueryParameters(array $parameters) + * @method static \Illuminate\Http\Client\PendingRequest contentType(string $contentType) + * @method static \Illuminate\Http\Client\PendingRequest acceptJson() + * @method static \Illuminate\Http\Client\PendingRequest accept(string $contentType) + * @method static \Illuminate\Http\Client\PendingRequest withHeaders(array $headers) + * @method static \Illuminate\Http\Client\PendingRequest withHeader(string $name, mixed $value) + * @method static \Illuminate\Http\Client\PendingRequest replaceHeaders(array $headers) + * @method static \Illuminate\Http\Client\PendingRequest withBasicAuth(string $username, string $password) + * @method static \Illuminate\Http\Client\PendingRequest withDigestAuth(string $username, string $password) + * @method static \Illuminate\Http\Client\PendingRequest withToken(string $token, string $type = 'Bearer') + * @method static \Illuminate\Http\Client\PendingRequest withUserAgent(string|bool $userAgent) + * @method static \Illuminate\Http\Client\PendingRequest withUrlParameters(array $parameters = []) + * @method static \Illuminate\Http\Client\PendingRequest withCookies(array $cookies, string $domain) + * @method static \Illuminate\Http\Client\PendingRequest maxRedirects(int $max) + * @method static \Illuminate\Http\Client\PendingRequest withoutRedirecting() + * @method static \Illuminate\Http\Client\PendingRequest withoutVerifying() + * @method static \Illuminate\Http\Client\PendingRequest sink(string|resource $to) + * @method static \Illuminate\Http\Client\PendingRequest timeout(int|float $seconds) + * @method static \Illuminate\Http\Client\PendingRequest connectTimeout(int|float $seconds) + * @method static \Illuminate\Http\Client\PendingRequest retry(array|int $times, \Closure|int $sleepMilliseconds = 0, callable|null $when = null, bool $throw = true) + * @method static \Illuminate\Http\Client\PendingRequest withOptions(array $options) + * @method static \Illuminate\Http\Client\PendingRequest withMiddleware(callable $middleware) + * @method static \Illuminate\Http\Client\PendingRequest withRequestMiddleware(callable $middleware) + * @method static \Illuminate\Http\Client\PendingRequest withResponseMiddleware(callable $middleware) + * @method static \Illuminate\Http\Client\PendingRequest beforeSending(callable $callback) + * @method static \Illuminate\Http\Client\PendingRequest throw(callable|null $callback = null) + * @method static \Illuminate\Http\Client\PendingRequest throwIf(callable|bool $condition) + * @method static \Illuminate\Http\Client\PendingRequest throwUnless(callable|bool $condition) + * @method static \Illuminate\Http\Client\PendingRequest dump() + * @method static \Illuminate\Http\Client\PendingRequest dd() + * @method static \Illuminate\Http\Client\Response get(string $url, array|string|null $query = null) + * @method static \Illuminate\Http\Client\Response head(string $url, array|string|null $query = null) + * @method static \Illuminate\Http\Client\Response post(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response patch(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response put(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static \Illuminate\Http\Client\Response delete(string $url, array|\JsonSerializable|\Illuminate\Contracts\Support\Arrayable $data = []) + * @method static array pool(callable $callback) + * @method static \Illuminate\Http\Client\Response send(string $method, string $url, array $options = []) + * @method static \GuzzleHttp\Client buildClient() + * @method static \GuzzleHttp\Client createClient(\GuzzleHttp\HandlerStack $handlerStack) + * @method static \GuzzleHttp\HandlerStack buildHandlerStack() + * @method static \GuzzleHttp\HandlerStack pushHandlers(\GuzzleHttp\HandlerStack $handlerStack) + * @method static \Closure buildBeforeSendingHandler() + * @method static \Closure buildRecorderHandler() + * @method static \Closure buildStubHandler() + * @method static \GuzzleHttp\Psr7\RequestInterface runBeforeSendingCallbacks(\GuzzleHttp\Psr7\RequestInterface $request, array $options) + * @method static array mergeOptions(array ...$options) + * @method static \Illuminate\Http\Client\PendingRequest stub(callable $callback) + * @method static \Illuminate\Http\Client\PendingRequest async(bool $async = true) + * @method static \GuzzleHttp\Promise\PromiseInterface|null getPromise() + * @method static \Illuminate\Http\Client\PendingRequest setClient(\GuzzleHttp\Client $client) + * @method static \Illuminate\Http\Client\PendingRequest setHandler(callable $handler) + * @method static array getOptions() + * @method static \Illuminate\Http\Client\PendingRequest|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @method static \Illuminate\Http\Client\PendingRequest|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @see \Illuminate\Http\Client\Factory + */ + class Http { + /** + * Add middleware to apply to every request. + * + * @param callable $middleware + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalMiddleware($middleware) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalMiddleware($middleware); + } + + /** + * Add request middleware to apply to every request. + * + * @param callable $middleware + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalRequestMiddleware($middleware) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalRequestMiddleware($middleware); + } + + /** + * Add response middleware to apply to every request. + * + * @param callable $middleware + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalResponseMiddleware($middleware) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalResponseMiddleware($middleware); + } + + /** + * Set the options to apply to every request. + * + * @param \Closure|array $options + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function globalOptions($options) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->globalOptions($options); + } + + /** + * Create a new response instance for use during stubbing. + * + * @param array|string|null $body + * @param int $status + * @param array $headers + * @return \GuzzleHttp\Promise\PromiseInterface + * @static + */ + public static function response($body = null, $status = 200, $headers = []) + { + return \Illuminate\Http\Client\Factory::response($body, $status, $headers); + } + + /** + * Create a new PSR-7 response instance for use during stubbing. + * + * @param array|string|null $body + * @param int $status + * @param array $headers + * @return \GuzzleHttp\Psr7\Response + * @static + */ + public static function psr7Response($body = null, $status = 200, $headers = []) + { + return \Illuminate\Http\Client\Factory::psr7Response($body, $status, $headers); + } + + /** + * Create a new RequestException instance for use during stubbing. + * + * @param array|string|null $body + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Client\RequestException + * @static + */ + public static function requestException($body = null, $status = 200, $headers = []) + { + return \Illuminate\Http\Client\Factory::requestException($body, $status, $headers); + } + + /** + * Create a new connection exception for use during stubbing. + * + * @param string|null $message + * @return \GuzzleHttp\Promise\PromiseInterface + * @static + */ + public static function failedConnection($message = null) + { + return \Illuminate\Http\Client\Factory::failedConnection($message); + } + + /** + * Get an invokable object that returns a sequence of responses in order for use during stubbing. + * + * @param array $responses + * @return \Illuminate\Http\Client\ResponseSequence + * @static + */ + public static function sequence($responses = []) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->sequence($responses); + } + + /** + * Register a stub callable that will intercept requests and be able to return stub responses. + * + * @param callable|array|null $callback + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function fake($callback = null) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->fake($callback); + } + + /** + * Register a response sequence for the given URL pattern. + * + * @param string $url + * @return \Illuminate\Http\Client\ResponseSequence + * @static + */ + public static function fakeSequence($url = '*') + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->fakeSequence($url); + } + + /** + * Stub the given URL using the given callback. + * + * @param string $url + * @param \Illuminate\Http\Client\Response|\GuzzleHttp\Promise\PromiseInterface|callable|int|string|array $callback + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function stubUrl($url, $callback) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->stubUrl($url, $callback); + } + + /** + * Indicate that an exception should be thrown if any request is not faked. + * + * @param bool $prevent + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function preventStrayRequests($prevent = true) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->preventStrayRequests($prevent); + } + + /** + * Determine if stray requests are being prevented. + * + * @return bool + * @static + */ + public static function preventingStrayRequests() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->preventingStrayRequests(); + } + + /** + * Indicate that an exception should not be thrown if any request is not faked. + * + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function allowStrayRequests() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->allowStrayRequests(); + } + + /** + * Begin recording request / response pairs. + * + * @return \Illuminate\Http\Client\Factory + * @static + */ + public static function record() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->record(); + } + + /** + * Record a request response pair. + * + * @param \Illuminate\Http\Client\Request $request + * @param \Illuminate\Http\Client\Response|null $response + * @return void + * @static + */ + public static function recordRequestResponsePair($request, $response) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->recordRequestResponsePair($request, $response); + } + + /** + * Assert that a request / response pair was recorded matching a given truth test. + * + * @param callable $callback + * @return void + * @static + */ + public static function assertSent($callback) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSent($callback); + } + + /** + * Assert that the given request was sent in the given order. + * + * @param array $callbacks + * @return void + * @static + */ + public static function assertSentInOrder($callbacks) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSentInOrder($callbacks); + } + + /** + * Assert that a request / response pair was not recorded matching a given truth test. + * + * @param callable $callback + * @return void + * @static + */ + public static function assertNotSent($callback) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertNotSent($callback); + } + + /** + * Assert that no request / response pair was recorded. + * + * @return void + * @static + */ + public static function assertNothingSent() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertNothingSent(); + } + + /** + * Assert how many requests have been recorded. + * + * @param int $count + * @return void + * @static + */ + public static function assertSentCount($count) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSentCount($count); + } + + /** + * Assert that every created response sequence is empty. + * + * @return void + * @static + */ + public static function assertSequencesAreEmpty() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + $instance->assertSequencesAreEmpty(); + } + + /** + * Get a collection of the request / response pairs matching the given truth test. + * + * @param callable $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function recorded($callback = null) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->recorded($callback); + } + + /** + * Create a new pending request instance for this factory. + * + * @return \Illuminate\Http\Client\PendingRequest + * @static + */ + public static function createPendingRequest() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->createPendingRequest(); + } + + /** + * Get the current event dispatcher implementation. + * + * @return \Illuminate\Contracts\Events\Dispatcher|null + * @static + */ + public static function getDispatcher() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->getDispatcher(); + } + + /** + * Get the array of global middleware. + * + * @return array + * @static + */ + public static function getGlobalMiddleware() + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->getGlobalMiddleware(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Http\Client\Factory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Http\Client\Factory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Http\Client\Factory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Http\Client\Factory::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Http\Client\Factory $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Translation\Translator + */ + class Lang { + /** + * Determine if a translation exists for a given locale. + * + * @param string $key + * @param string|null $locale + * @return bool + * @static + */ + public static function hasForLocale($key, $locale = null) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->hasForLocale($key, $locale); + } + + /** + * Determine if a translation exists. + * + * @param string $key + * @param string|null $locale + * @param bool $fallback + * @return bool + * @static + */ + public static function has($key, $locale = null, $fallback = true) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->has($key, $locale, $fallback); + } + + /** + * Get the translation for the given key. + * + * @param string $key + * @param array $replace + * @param string|null $locale + * @param bool $fallback + * @return string|array + * @static + */ + public static function get($key, $replace = [], $locale = null, $fallback = true) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->get($key, $replace, $locale, $fallback); + } + + /** + * Get a translation according to an integer value. + * + * @param string $key + * @param \Countable|int|float|array $number + * @param array $replace + * @param string|null $locale + * @return string + * @static + */ + public static function choice($key, $number, $replace = [], $locale = null) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->choice($key, $number, $replace, $locale); + } + + /** + * Add translation lines to the given locale. + * + * @param array $lines + * @param string $locale + * @param string $namespace + * @return void + * @static + */ + public static function addLines($lines, $locale, $namespace = '*') + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addLines($lines, $locale, $namespace); + } + + /** + * Load the specified language group. + * + * @param string $namespace + * @param string $group + * @param string $locale + * @return void + * @static + */ + public static function load($namespace, $group, $locale) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->load($namespace, $group, $locale); + } + + /** + * Register a callback that is responsible for handling missing translation keys. + * + * @param callable|null $callback + * @return static + * @static + */ + public static function handleMissingKeysUsing($callback) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->handleMissingKeysUsing($callback); + } + + /** + * Add a new namespace to the loader. + * + * @param string $namespace + * @param string $hint + * @return void + * @static + */ + public static function addNamespace($namespace, $hint) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addNamespace($namespace, $hint); + } + + /** + * Add a new path to the loader. + * + * @param string $path + * @return void + * @static + */ + public static function addPath($path) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addPath($path); + } + + /** + * Add a new JSON path to the loader. + * + * @param string $path + * @return void + * @static + */ + public static function addJsonPath($path) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->addJsonPath($path); + } + + /** + * Parse a key into namespace, group, and item. + * + * @param string $key + * @return array + * @static + */ + public static function parseKey($key) + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->parseKey($key); + } + + /** + * Specify a callback that should be invoked to determined the applicable locale array. + * + * @param callable $callback + * @return void + * @static + */ + public static function determineLocalesUsing($callback) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->determineLocalesUsing($callback); + } + + /** + * Get the message selector instance. + * + * @return \Illuminate\Translation\MessageSelector + * @static + */ + public static function getSelector() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getSelector(); + } + + /** + * Set the message selector instance. + * + * @param \Illuminate\Translation\MessageSelector $selector + * @return void + * @static + */ + public static function setSelector($selector) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setSelector($selector); + } + + /** + * Get the language line loader implementation. + * + * @return \Illuminate\Contracts\Translation\Loader + * @static + */ + public static function getLoader() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getLoader(); + } + + /** + * Get the default locale being used. + * + * @return string + * @static + */ + public static function locale() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->locale(); + } + + /** + * Get the default locale being used. + * + * @return string + * @static + */ + public static function getLocale() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getLocale(); + } + + /** + * Set the default locale. + * + * @param string $locale + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function setLocale($locale) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setLocale($locale); + } + + /** + * Get the fallback locale being used. + * + * @return string + * @static + */ + public static function getFallback() + { + /** @var \Illuminate\Translation\Translator $instance */ + return $instance->getFallback(); + } + + /** + * Set the fallback locale being used. + * + * @param string $fallback + * @return void + * @static + */ + public static function setFallback($fallback) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setFallback($fallback); + } + + /** + * Set the loaded translation groups. + * + * @param array $loaded + * @return void + * @static + */ + public static function setLoaded($loaded) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setLoaded($loaded); + } + + /** + * Add a handler to be executed in order to format a given class to a string during translation replacements. + * + * @param callable|string $class + * @param callable|null $handler + * @return void + * @static + */ + public static function stringable($class, $handler = null) + { + /** @var \Illuminate\Translation\Translator $instance */ + $instance->stringable($class, $handler); + } + + /** + * Set the parsed value of a key. + * + * @param string $key + * @param array $parsed + * @return void + * @static + */ + public static function setParsedKey($key, $parsed) + { + //Method inherited from \Illuminate\Support\NamespacedItemResolver + /** @var \Illuminate\Translation\Translator $instance */ + $instance->setParsedKey($key, $parsed); + } + + /** + * Flush the cache of parsed keys. + * + * @return void + * @static + */ + public static function flushParsedKeys() + { + //Method inherited from \Illuminate\Support\NamespacedItemResolver + /** @var \Illuminate\Translation\Translator $instance */ + $instance->flushParsedKeys(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Translation\Translator::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Translation\Translator::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Translation\Translator::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Translation\Translator::flushMacros(); + } + + } + /** + * + * + * @method static void write(string $level, \Illuminate\Contracts\Support\Arrayable|\Illuminate\Contracts\Support\Jsonable|\Illuminate\Support\Stringable|array|string $message, array $context = []) + * @method static \Illuminate\Log\Logger withContext(array $context = []) + * @method static void listen(\Closure $callback) + * @method static \Psr\Log\LoggerInterface getLogger() + * @method static \Illuminate\Contracts\Events\Dispatcher getEventDispatcher() + * @method static void setEventDispatcher(\Illuminate\Contracts\Events\Dispatcher $dispatcher) + * @method static \Illuminate\Log\Logger|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @method static \Illuminate\Log\Logger|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @see \Illuminate\Log\LogManager + */ + class Log { + /** + * Build an on-demand log channel. + * + * @param array $config + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->build($config); + } + + /** + * Create a new, on-demand aggregate logger instance. + * + * @param array $channels + * @param string|null $channel + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function stack($channels, $channel = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->stack($channels, $channel); + } + + /** + * Get a log channel instance. + * + * @param string|null $channel + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function channel($channel = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->channel($channel); + } + + /** + * Get a log driver instance. + * + * @param string|null $driver + * @return \Psr\Log\LoggerInterface + * @static + */ + public static function driver($driver = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->driver($driver); + } + + /** + * Share context across channels and stacks. + * + * @param array $context + * @return \Illuminate\Log\LogManager + * @static + */ + public static function shareContext($context) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->shareContext($context); + } + + /** + * The context shared across channels and stacks. + * + * @return array + * @static + */ + public static function sharedContext() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->sharedContext(); + } + + /** + * Flush the log context on all currently resolved channels. + * + * @param string[]|null $keys + * @return \Illuminate\Log\LogManager + * @static + */ + public static function withoutContext($keys = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->withoutContext($keys); + } + + /** + * Flush the shared context. + * + * @return \Illuminate\Log\LogManager + * @static + */ + public static function flushSharedContext() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->flushSharedContext(); + } + + /** + * Get the default log driver name. + * + * @return string|null + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default log driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @param-closure-this $this $callback + * @return \Illuminate\Log\LogManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Unset the given channel instance. + * + * @param string|null $driver + * @return void + * @static + */ + public static function forgetChannel($driver = null) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->forgetChannel($driver); + } + + /** + * Get all of the resolved log channels. + * + * @return array + * @static + */ + public static function getChannels() + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->getChannels(); + } + + /** + * System is unusable. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function emergency($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->emergency($message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function alert($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->alert($message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function critical($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->critical($message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function error($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->error($message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function warning($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->warning($message, $context); + } + + /** + * Normal but significant events. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function notice($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->notice($message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function info($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->info($message, $context); + } + + /** + * Detailed debug information. + * + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function debug($message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->debug($message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string|\Stringable $message + * @param array $context + * @return void + * @static + */ + public static function log($level, $message, $context = []) + { + /** @var \Illuminate\Log\LogManager $instance */ + $instance->log($level, $message, $context); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Log\LogManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Log\LogManager $instance */ + return $instance->setApplication($app); + } + + } + /** + * + * + * @method static void alwaysFrom(string $address, string|null $name = null) + * @method static void alwaysReplyTo(string $address, string|null $name = null) + * @method static void alwaysReturnPath(string $address) + * @method static void alwaysTo(string $address, string|null $name = null) + * @method static \Illuminate\Mail\SentMessage|null html(string $html, mixed $callback) + * @method static \Illuminate\Mail\SentMessage|null plain(string $view, array $data, mixed $callback) + * @method static string render(string|array $view, array $data = []) + * @method static mixed onQueue(\BackedEnum|string|null $queue, \Illuminate\Contracts\Mail\Mailable $view) + * @method static mixed queueOn(string $queue, \Illuminate\Contracts\Mail\Mailable $view) + * @method static mixed laterOn(string $queue, \DateTimeInterface|\DateInterval|int $delay, \Illuminate\Contracts\Mail\Mailable $view) + * @method static \Symfony\Component\Mailer\Transport\TransportInterface getSymfonyTransport() + * @method static \Illuminate\Contracts\View\Factory getViewFactory() + * @method static void setSymfonyTransport(\Symfony\Component\Mailer\Transport\TransportInterface $transport) + * @method static \Illuminate\Mail\Mailer setQueue(\Illuminate\Contracts\Queue\Factory $queue) + * @method static void macro(string $name, object|callable $macro) + * @method static void mixin(object $mixin, bool $replace = true) + * @method static bool hasMacro(string $name) + * @method static void flushMacros() + * @see \Illuminate\Mail\MailManager + * @see \Illuminate\Support\Testing\Fakes\MailFake + */ + class Mail { + /** + * Get a mailer instance by name. + * + * @param string|null $name + * @return \Illuminate\Contracts\Mail\Mailer + * @static + */ + public static function mailer($name = null) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->mailer($name); + } + + /** + * Get a mailer driver instance. + * + * @param string|null $driver + * @return \Illuminate\Mail\Mailer + * @static + */ + public static function driver($driver = null) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->driver($driver); + } + + /** + * Build a new mailer instance. + * + * @param array $config + * @return \Illuminate\Mail\Mailer + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->build($config); + } + + /** + * Create a new transport instance. + * + * @param array $config + * @return \Symfony\Component\Mailer\Transport\TransportInterface + * @throws \InvalidArgumentException + * @static + */ + public static function createSymfonyTransport($config) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->createSymfonyTransport($config); + } + + /** + * Get the default mail driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default mail driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Mail\MailManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Disconnect the given mailer and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Mail\MailManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom transport creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Mail\MailManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + * @static + */ + public static function getApplication() + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->getApplication(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Mail\MailManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->setApplication($app); + } + + /** + * Forget all of the resolved mailer instances. + * + * @return \Illuminate\Mail\MailManager + * @static + */ + public static function forgetMailers() + { + /** @var \Illuminate\Mail\MailManager $instance */ + return $instance->forgetMailers(); + } + + /** + * Assert if a mailable was sent based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|int|null $callback + * @return void + * @static + */ + public static function assertSent($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertSent($mailable, $callback); + } + + /** + * Determine if a mailable was not sent or queued to be sent based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotOutgoing($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNotOutgoing($mailable, $callback); + } + + /** + * Determine if a mailable was not sent based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|null $callback + * @return void + * @static + */ + public static function assertNotSent($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNotSent($mailable, $callback); + } + + /** + * Assert that no mailables were sent or queued to be sent. + * + * @return void + * @static + */ + public static function assertNothingOutgoing() + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNothingOutgoing(); + } + + /** + * Assert that no mailables were sent. + * + * @return void + * @static + */ + public static function assertNothingSent() + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNothingSent(); + } + + /** + * Assert if a mailable was queued based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|int|null $callback + * @return void + * @static + */ + public static function assertQueued($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertQueued($mailable, $callback); + } + + /** + * Determine if a mailable was not queued based on a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|array|string|null $callback + * @return void + * @static + */ + public static function assertNotQueued($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNotQueued($mailable, $callback); + } + + /** + * Assert that no mailables were queued. + * + * @return void + * @static + */ + public static function assertNothingQueued() + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertNothingQueued(); + } + + /** + * Assert the total number of mailables that were sent. + * + * @param int $count + * @return void + * @static + */ + public static function assertSentCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertSentCount($count); + } + + /** + * Assert the total number of mailables that were queued. + * + * @param int $count + * @return void + * @static + */ + public static function assertQueuedCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertQueuedCount($count); + } + + /** + * Assert the total number of mailables that were sent or queued. + * + * @param int $count + * @return void + * @static + */ + public static function assertOutgoingCount($count) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->assertOutgoingCount($count); + } + + /** + * Get all of the mailables matching a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function sent($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->sent($mailable, $callback); + } + + /** + * Determine if the given mailable has been sent. + * + * @param string $mailable + * @return bool + * @static + */ + public static function hasSent($mailable) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->hasSent($mailable); + } + + /** + * Get all of the queued mailables matching a truth-test callback. + * + * @param string|\Closure $mailable + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function queued($mailable, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->queued($mailable, $callback); + } + + /** + * Determine if the given mailable has been queued. + * + * @param string $mailable + * @return bool + * @static + */ + public static function hasQueued($mailable) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->hasQueued($mailable); + } + + /** + * Begin the process of mailing a mailable class instance. + * + * @param mixed $users + * @return \Illuminate\Mail\PendingMail + * @static + */ + public static function to($users) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->to($users); + } + + /** + * Begin the process of mailing a mailable class instance. + * + * @param mixed $users + * @return \Illuminate\Mail\PendingMail + * @static + */ + public static function cc($users) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->cc($users); + } + + /** + * Begin the process of mailing a mailable class instance. + * + * @param mixed $users + * @return \Illuminate\Mail\PendingMail + * @static + */ + public static function bcc($users) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->bcc($users); + } + + /** + * Send a new message with only a raw text part. + * + * @param string $text + * @param \Closure|string $callback + * @return void + * @static + */ + public static function raw($text, $callback) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->raw($text, $callback); + } + + /** + * Send a new message using a view. + * + * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param array $data + * @param \Closure|string|null $callback + * @return mixed|void + * @static + */ + public static function send($view, $data = [], $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->send($view, $data, $callback); + } + + /** + * Send a new message synchronously using a view. + * + * @param \Illuminate\Contracts\Mail\Mailable|string|array $mailable + * @param array $data + * @param \Closure|string|null $callback + * @return void + * @static + */ + public static function sendNow($mailable, $data = [], $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + $instance->sendNow($mailable, $data, $callback); + } + + /** + * Queue a new message for sending. + * + * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param string|null $queue + * @return mixed + * @static + */ + public static function queue($view, $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->queue($view, $queue); + } + + /** + * Queue a new e-mail message for sending after (n) seconds. + * + * @param \DateTimeInterface|\DateInterval|int $delay + * @param \Illuminate\Contracts\Mail\Mailable|string|array $view + * @param string|null $queue + * @return mixed + * @static + */ + public static function later($delay, $view, $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\MailFake $instance */ + return $instance->later($delay, $view, $queue); + } + + } + /** + * + * + * @see \Illuminate\Notifications\ChannelManager + * @see \Illuminate\Support\Testing\Fakes\NotificationFake + */ + class Notification { + /** + * Send the given notification to the given notifiable entities. + * + * @param \Illuminate\Support\Collection|array|mixed $notifiables + * @param mixed $notification + * @return void + * @static + */ + public static function send($notifiables, $notification) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + $instance->send($notifiables, $notification); + } + + /** + * Send the given notification immediately. + * + * @param \Illuminate\Support\Collection|array|mixed $notifiables + * @param mixed $notification + * @param array|null $channels + * @return void + * @static + */ + public static function sendNow($notifiables, $notification, $channels = null) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + $instance->sendNow($notifiables, $notification, $channels); + } + + /** + * Get a channel instance. + * + * @param string|null $name + * @return mixed + * @static + */ + public static function channel($name = null) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->channel($name); + } + + /** + * Get the default channel driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Get the default channel driver name. + * + * @return string + * @static + */ + public static function deliversVia() + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->deliversVia(); + } + + /** + * Set the default channel driver name. + * + * @param string $channel + * @return void + * @static + */ + public static function deliverVia($channel) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + $instance->deliverVia($channel); + } + + /** + * Set the locale of notifications. + * + * @param string $locale + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function locale($locale) + { + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->locale($locale); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function driver($driver = null) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->driver($driver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function extend($driver, $callback) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get all of the created "drivers". + * + * @return array + * @static + */ + public static function getDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->getDrivers(); + } + + /** + * Get the container instance used by the manager. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the manager. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->setContainer($container); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Notifications\ChannelManager + * @static + */ + public static function forgetDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Notifications\ChannelManager $instance */ + return $instance->forgetDrivers(); + } + + /** + * Assert if a notification was sent on-demand based on a truth-test callback. + * + * @param string|\Closure $notification + * @param callable|null $callback + * @return void + * @throws \Exception + * @static + */ + public static function assertSentOnDemand($notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentOnDemand($notification, $callback); + } + + /** + * Assert if a notification was sent based on a truth-test callback. + * + * @param mixed $notifiable + * @param string|\Closure $notification + * @param callable|null $callback + * @return void + * @throws \Exception + * @static + */ + public static function assertSentTo($notifiable, $notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentTo($notifiable, $notification, $callback); + } + + /** + * Assert if a notification was sent on-demand a number of times. + * + * @param string $notification + * @param int $times + * @return void + * @static + */ + public static function assertSentOnDemandTimes($notification, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentOnDemandTimes($notification, $times); + } + + /** + * Assert if a notification was sent a number of times. + * + * @param mixed $notifiable + * @param string $notification + * @param int $times + * @return void + * @static + */ + public static function assertSentToTimes($notifiable, $notification, $times = 1) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentToTimes($notifiable, $notification, $times); + } + + /** + * Determine if a notification was sent based on a truth-test callback. + * + * @param mixed $notifiable + * @param string|\Closure $notification + * @param callable|null $callback + * @return void + * @throws \Exception + * @static + */ + public static function assertNotSentTo($notifiable, $notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertNotSentTo($notifiable, $notification, $callback); + } + + /** + * Assert that no notifications were sent. + * + * @return void + * @static + */ + public static function assertNothingSent() + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertNothingSent(); + } + + /** + * Assert that no notifications were sent to the given notifiable. + * + * @param mixed $notifiable + * @return void + * @throws \Exception + * @static + */ + public static function assertNothingSentTo($notifiable) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertNothingSentTo($notifiable); + } + + /** + * Assert the total amount of times a notification was sent. + * + * @param string $notification + * @param int $expectedCount + * @return void + * @static + */ + public static function assertSentTimes($notification, $expectedCount) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertSentTimes($notification, $expectedCount); + } + + /** + * Assert the total count of notification that were sent. + * + * @param int $expectedCount + * @return void + * @static + */ + public static function assertCount($expectedCount) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + $instance->assertCount($expectedCount); + } + + /** + * Get all of the notifications matching a truth-test callback. + * + * @param mixed $notifiable + * @param string $notification + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function sent($notifiable, $notification, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->sent($notifiable, $notification, $callback); + } + + /** + * Determine if there are more notifications left to inspect. + * + * @param mixed $notifiable + * @param string $notification + * @return bool + * @static + */ + public static function hasSent($notifiable, $notification) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->hasSent($notifiable, $notification); + } + + /** + * Specify if notification should be serialized and restored when being "pushed" to the queue. + * + * @param bool $serializeAndRestore + * @return \Illuminate\Support\Testing\Fakes\NotificationFake + * @static + */ + public static function serializeAndRestore($serializeAndRestore = true) + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->serializeAndRestore($serializeAndRestore); + } + + /** + * Get the notifications that have been sent. + * + * @return array + * @static + */ + public static function sentNotifications() + { + /** @var \Illuminate\Support\Testing\Fakes\NotificationFake $instance */ + return $instance->sentNotifications(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Support\Testing\Fakes\NotificationFake::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Support\Testing\Fakes\NotificationFake::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Support\Testing\Fakes\NotificationFake::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Support\Testing\Fakes\NotificationFake::flushMacros(); + } + + } + /** + * + * + * @method static string sendResetLink(array $credentials, \Closure|null $callback = null) + * @method static mixed reset(array $credentials, \Closure $callback) + * @method static \Illuminate\Contracts\Auth\CanResetPassword|null getUser(array $credentials) + * @method static string createToken(\Illuminate\Contracts\Auth\CanResetPassword $user) + * @method static void deleteToken(\Illuminate\Contracts\Auth\CanResetPassword $user) + * @method static bool tokenExists(\Illuminate\Contracts\Auth\CanResetPassword $user, string $token) + * @method static \Illuminate\Auth\Passwords\TokenRepositoryInterface getRepository() + * @see \Illuminate\Auth\Passwords\PasswordBrokerManager + * @see \Illuminate\Auth\Passwords\PasswordBroker + */ + class Password { + /** + * Attempt to get the broker from the local cache. + * + * @param string|null $name + * @return \Illuminate\Contracts\Auth\PasswordBroker + * @static + */ + public static function broker($name = null) + { + /** @var \Illuminate\Auth\Passwords\PasswordBrokerManager $instance */ + return $instance->broker($name); + } + + /** + * Get the default password broker name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Auth\Passwords\PasswordBrokerManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default password broker name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Auth\Passwords\PasswordBrokerManager $instance */ + $instance->setDefaultDriver($name); + } + + } + /** + * + * + * @method static \Illuminate\Process\PendingProcess command(array|string $command) + * @method static \Illuminate\Process\PendingProcess path(string $path) + * @method static \Illuminate\Process\PendingProcess timeout(int $timeout) + * @method static \Illuminate\Process\PendingProcess idleTimeout(int $timeout) + * @method static \Illuminate\Process\PendingProcess forever() + * @method static \Illuminate\Process\PendingProcess env(array $environment) + * @method static \Illuminate\Process\PendingProcess input(\Traversable|resource|string|int|float|bool|null $input) + * @method static \Illuminate\Process\PendingProcess quietly() + * @method static \Illuminate\Process\PendingProcess tty(bool $tty = true) + * @method static \Illuminate\Process\PendingProcess options(array $options) + * @method static \Illuminate\Contracts\Process\ProcessResult run(array|string|null $command = null, callable|null $output = null) + * @method static \Illuminate\Process\InvokedProcess start(array|string|null $command = null, callable|null $output = null) + * @method static bool supportsTty() + * @method static \Illuminate\Process\PendingProcess withFakeHandlers(array $fakeHandlers) + * @method static \Illuminate\Process\PendingProcess|mixed when(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @method static \Illuminate\Process\PendingProcess|mixed unless(\Closure|mixed|null $value = null, callable|null $callback = null, callable|null $default = null) + * @see \Illuminate\Process\PendingProcess + * @see \Illuminate\Process\Factory + */ + class Process { + /** + * Create a new fake process response for testing purposes. + * + * @param array|string $output + * @param array|string $errorOutput + * @param int $exitCode + * @return \Illuminate\Process\FakeProcessResult + * @static + */ + public static function result($output = '', $errorOutput = '', $exitCode = 0) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->result($output, $errorOutput, $exitCode); + } + + /** + * Begin describing a fake process lifecycle. + * + * @return \Illuminate\Process\FakeProcessDescription + * @static + */ + public static function describe() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->describe(); + } + + /** + * Begin describing a fake process sequence. + * + * @param array $processes + * @return \Illuminate\Process\FakeProcessSequence + * @static + */ + public static function sequence($processes = []) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->sequence($processes); + } + + /** + * Indicate that the process factory should fake processes. + * + * @param \Closure|array|null $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function fake($callback = null) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->fake($callback); + } + + /** + * Determine if the process factory has fake process handlers and is recording processes. + * + * @return bool + * @static + */ + public static function isRecording() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->isRecording(); + } + + /** + * Record the given process if processes should be recorded. + * + * @param \Illuminate\Process\PendingProcess $process + * @param \Illuminate\Contracts\Process\ProcessResult $result + * @return \Illuminate\Process\Factory + * @static + */ + public static function recordIfRecording($process, $result) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->recordIfRecording($process, $result); + } + + /** + * Record the given process. + * + * @param \Illuminate\Process\PendingProcess $process + * @param \Illuminate\Contracts\Process\ProcessResult $result + * @return \Illuminate\Process\Factory + * @static + */ + public static function record($process, $result) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->record($process, $result); + } + + /** + * Indicate that an exception should be thrown if any process is not faked. + * + * @param bool $prevent + * @return \Illuminate\Process\Factory + * @static + */ + public static function preventStrayProcesses($prevent = true) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->preventStrayProcesses($prevent); + } + + /** + * Determine if stray processes are being prevented. + * + * @return bool + * @static + */ + public static function preventingStrayProcesses() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->preventingStrayProcesses(); + } + + /** + * Assert that a process was recorded matching a given truth test. + * + * @param \Closure|string $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertRan($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertRan($callback); + } + + /** + * Assert that a process was recorded a given number of times matching a given truth test. + * + * @param \Closure|string $callback + * @param int $times + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertRanTimes($callback, $times = 1) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertRanTimes($callback, $times); + } + + /** + * Assert that a process was not recorded matching a given truth test. + * + * @param \Closure|string $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertNotRan($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertNotRan($callback); + } + + /** + * Assert that a process was not recorded matching a given truth test. + * + * @param \Closure|string $callback + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertDidntRun($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertDidntRun($callback); + } + + /** + * Assert that no processes were recorded. + * + * @return \Illuminate\Process\Factory + * @static + */ + public static function assertNothingRan() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->assertNothingRan(); + } + + /** + * Start defining a pool of processes. + * + * @param callable $callback + * @return \Illuminate\Process\Pool + * @static + */ + public static function pool($callback) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->pool($callback); + } + + /** + * Start defining a series of piped processes. + * + * @param callable|array $callback + * @return \Illuminate\Contracts\Process\ProcessResult + * @static + */ + public static function pipe($callback, $output = null) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->pipe($callback, $output); + } + + /** + * Run a pool of processes and wait for them to finish executing. + * + * @param callable $callback + * @param callable|null $output + * @return \Illuminate\Process\ProcessPoolResults + * @static + */ + public static function concurrently($callback, $output = null) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->concurrently($callback, $output); + } + + /** + * Create a new pending process associated with this factory. + * + * @return \Illuminate\Process\PendingProcess + * @static + */ + public static function newPendingProcess() + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->newPendingProcess(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Process\Factory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Process\Factory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Process\Factory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Process\Factory::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Process\Factory $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Queue\QueueManager + * @see \Illuminate\Queue\Queue + * @see \Illuminate\Support\Testing\Fakes\QueueFake + */ + class Queue { + /** + * Register an event listener for the before job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function before($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->before($callback); + } + + /** + * Register an event listener for the after job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function after($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->after($callback); + } + + /** + * Register an event listener for the exception occurred job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function exceptionOccurred($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->exceptionOccurred($callback); + } + + /** + * Register an event listener for the daemon queue loop. + * + * @param mixed $callback + * @return void + * @static + */ + public static function looping($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->looping($callback); + } + + /** + * Register an event listener for the failed job event. + * + * @param mixed $callback + * @return void + * @static + */ + public static function failing($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->failing($callback); + } + + /** + * Register an event listener for the daemon queue stopping. + * + * @param mixed $callback + * @return void + * @static + */ + public static function stopping($callback) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->stopping($callback); + } + + /** + * Determine if the driver is connected. + * + * @param string|null $name + * @return bool + * @static + */ + public static function connected($name = null) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->connected($name); + } + + /** + * Resolve a queue connection instance. + * + * @param string|null $name + * @return \Illuminate\Contracts\Queue\Queue + * @static + */ + public static function connection($name = null) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->connection($name); + } + + /** + * Add a queue connection resolver. + * + * @param string $driver + * @param \Closure $resolver + * @return void + * @static + */ + public static function extend($driver, $resolver) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->extend($driver, $resolver); + } + + /** + * Add a queue connection resolver. + * + * @param string $driver + * @param \Closure $resolver + * @return void + * @static + */ + public static function addConnector($driver, $resolver) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->addConnector($driver, $resolver); + } + + /** + * Get the name of the default queue connection. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the name of the default queue connection. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Get the full name for the given connection. + * + * @param string|null $connection + * @return string + * @static + */ + public static function getName($connection = null) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->getName($connection); + } + + /** + * Get the application instance used by the manager. + * + * @return \Illuminate\Contracts\Foundation\Application + * @static + */ + public static function getApplication() + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->getApplication(); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Queue\QueueManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Queue\QueueManager $instance */ + return $instance->setApplication($app); + } + + /** + * Specify the jobs that should be queued instead of faked. + * + * @param array|string $jobsToBeQueued + * @return \Illuminate\Support\Testing\Fakes\QueueFake + * @static + */ + public static function except($jobsToBeQueued) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->except($jobsToBeQueued); + } + + /** + * Assert if a job was pushed based on a truth-test callback. + * + * @param string|\Closure $job + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertPushed($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushed($job, $callback); + } + + /** + * Assert if a job was pushed based on a truth-test callback. + * + * @param string $queue + * @param string|\Closure $job + * @param callable|null $callback + * @return void + * @static + */ + public static function assertPushedOn($queue, $job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushedOn($queue, $job, $callback); + } + + /** + * Assert if a job was pushed with chained jobs based on a truth-test callback. + * + * @param string $job + * @param array $expectedChain + * @param callable|null $callback + * @return void + * @static + */ + public static function assertPushedWithChain($job, $expectedChain = [], $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushedWithChain($job, $expectedChain, $callback); + } + + /** + * Assert if a job was pushed with an empty chain based on a truth-test callback. + * + * @param string $job + * @param callable|null $callback + * @return void + * @static + */ + public static function assertPushedWithoutChain($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertPushedWithoutChain($job, $callback); + } + + /** + * Assert if a closure was pushed based on a truth-test callback. + * + * @param callable|int|null $callback + * @return void + * @static + */ + public static function assertClosurePushed($callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertClosurePushed($callback); + } + + /** + * Assert that a closure was not pushed based on a truth-test callback. + * + * @param callable|null $callback + * @return void + * @static + */ + public static function assertClosureNotPushed($callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertClosureNotPushed($callback); + } + + /** + * Determine if a job was pushed based on a truth-test callback. + * + * @param string|\Closure $job + * @param callable|null $callback + * @return void + * @static + */ + public static function assertNotPushed($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertNotPushed($job, $callback); + } + + /** + * Assert the total count of jobs that were pushed. + * + * @param int $expectedCount + * @return void + * @static + */ + public static function assertCount($expectedCount) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertCount($expectedCount); + } + + /** + * Assert that no jobs were pushed. + * + * @return void + * @static + */ + public static function assertNothingPushed() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + $instance->assertNothingPushed(); + } + + /** + * Get all of the jobs matching a truth-test callback. + * + * @param string $job + * @param callable|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function pushed($job, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushed($job, $callback); + } + + /** + * Get all of the raw pushes matching a truth-test callback. + * + * @param null|\Closure(string, ?string, array): bool $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function pushedRaw($callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushedRaw($callback); + } + + /** + * Get all of the jobs by listener class, passing an optional truth-test callback. + * + * @param class-string $listenerClass + * @param (\Closure(mixed, \Illuminate\Events\CallQueuedListener, string|null, mixed): bool)|null $callback + * @return \Illuminate\Support\Collection + * @static + */ + public static function listenersPushed($listenerClass, $callback = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->listenersPushed($listenerClass, $callback); + } + + /** + * Determine if there are any stored jobs for a given class. + * + * @param string $job + * @return bool + * @static + */ + public static function hasPushed($job) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->hasPushed($job); + } + + /** + * Get the size of the queue. + * + * @param string|null $queue + * @return int + * @static + */ + public static function size($queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->size($queue); + } + + /** + * Push a new job onto the queue. + * + * @param string|object $job + * @param mixed $data + * @param string|null $queue + * @return mixed + * @static + */ + public static function push($job, $data = '', $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->push($job, $data, $queue); + } + + /** + * Determine if a job should be faked or actually dispatched. + * + * @param object $job + * @return bool + * @static + */ + public static function shouldFakeJob($job) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->shouldFakeJob($job); + } + + /** + * Push a raw payload onto the queue. + * + * @param string $payload + * @param string|null $queue + * @param array $options + * @return mixed + * @static + */ + public static function pushRaw($payload, $queue = null, $options = []) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushRaw($payload, $queue, $options); + } + + /** + * Push a new job onto the queue after (n) seconds. + * + * @param \DateTimeInterface|\DateInterval|int $delay + * @param string|object $job + * @param mixed $data + * @param string|null $queue + * @return mixed + * @static + */ + public static function later($delay, $job, $data = '', $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->later($delay, $job, $data, $queue); + } + + /** + * Push a new job onto the queue. + * + * @param string $queue + * @param string|object $job + * @param mixed $data + * @return mixed + * @static + */ + public static function pushOn($queue, $job, $data = '') + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushOn($queue, $job, $data); + } + + /** + * Push a new job onto a specific queue after (n) seconds. + * + * @param string $queue + * @param \DateTimeInterface|\DateInterval|int $delay + * @param string|object $job + * @param mixed $data + * @return mixed + * @static + */ + public static function laterOn($queue, $delay, $job, $data = '') + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->laterOn($queue, $delay, $job, $data); + } + + /** + * Pop the next job off of the queue. + * + * @param string|null $queue + * @return \Illuminate\Contracts\Queue\Job|null + * @static + */ + public static function pop($queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pop($queue); + } + + /** + * Push an array of jobs onto the queue. + * + * @param array $jobs + * @param mixed $data + * @param string|null $queue + * @return mixed + * @static + */ + public static function bulk($jobs, $data = '', $queue = null) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->bulk($jobs, $data, $queue); + } + + /** + * Get the jobs that have been pushed. + * + * @return array + * @static + */ + public static function pushedJobs() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->pushedJobs(); + } + + /** + * Get the payloads that were pushed raw. + * + * @return list + * @static + */ + public static function rawPushes() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->rawPushes(); + } + + /** + * Specify if jobs should be serialized and restored when being "pushed" to the queue. + * + * @param bool $serializeAndRestore + * @return \Illuminate\Support\Testing\Fakes\QueueFake + * @static + */ + public static function serializeAndRestore($serializeAndRestore = true) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->serializeAndRestore($serializeAndRestore); + } + + /** + * Get the connection name for the queue. + * + * @return string + * @static + */ + public static function getConnectionName() + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->getConnectionName(); + } + + /** + * Set the connection name for the queue. + * + * @param string $name + * @return \Illuminate\Support\Testing\Fakes\QueueFake + * @static + */ + public static function setConnectionName($name) + { + /** @var \Illuminate\Support\Testing\Fakes\QueueFake $instance */ + return $instance->setConnectionName($name); + } + + /** + * Release a reserved job back onto the queue after (n) seconds. + * + * @param string $queue + * @param \Illuminate\Queue\Jobs\DatabaseJobRecord $job + * @param int $delay + * @return mixed + * @static + */ + public static function release($queue, $job, $delay) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->release($queue, $job, $delay); + } + + /** + * Delete a reserved job from the queue. + * + * @param string $queue + * @param string $id + * @return void + * @throws \Throwable + * @static + */ + public static function deleteReserved($queue, $id) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + $instance->deleteReserved($queue, $id); + } + + /** + * Delete a reserved job from the reserved queue and release it. + * + * @param string $queue + * @param \Illuminate\Queue\Jobs\DatabaseJob $job + * @param int $delay + * @return void + * @static + */ + public static function deleteAndRelease($queue, $job, $delay) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + $instance->deleteAndRelease($queue, $job, $delay); + } + + /** + * Delete all of the jobs from the queue. + * + * @param string $queue + * @return int + * @static + */ + public static function clear($queue) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->clear($queue); + } + + /** + * Get the queue or return the default. + * + * @param string|null $queue + * @return string + * @static + */ + public static function getQueue($queue) + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getQueue($queue); + } + + /** + * Get the underlying database instance. + * + * @return \Illuminate\Database\Connection + * @static + */ + public static function getDatabase() + { + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getDatabase(); + } + + /** + * Get the maximum number of attempts for an object-based queue handler. + * + * @param mixed $job + * @return mixed + * @static + */ + public static function getJobTries($job) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getJobTries($job); + } + + /** + * Get the backoff for an object-based queue handler. + * + * @param mixed $job + * @return mixed + * @static + */ + public static function getJobBackoff($job) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getJobBackoff($job); + } + + /** + * Get the expiration timestamp for an object-based queue handler. + * + * @param mixed $job + * @return mixed + * @static + */ + public static function getJobExpiration($job) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getJobExpiration($job); + } + + /** + * Register a callback to be executed when creating job payloads. + * + * @param callable|null $callback + * @return void + * @static + */ + public static function createPayloadUsing($callback) + { + //Method inherited from \Illuminate\Queue\Queue + \Illuminate\Queue\DatabaseQueue::createPayloadUsing($callback); + } + + /** + * Get the container instance being used by the connection. + * + * @return \Illuminate\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + return $instance->getContainer(); + } + + /** + * Set the IoC container instance. + * + * @param \Illuminate\Container\Container $container + * @return void + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Queue\Queue + /** @var \Illuminate\Queue\DatabaseQueue $instance */ + $instance->setContainer($container); + } + + } + /** + * + * + * @see \Illuminate\Cache\RateLimiter + */ + class RateLimiter { + /** + * Register a named limiter configuration. + * + * @param \BackedEnum|\UnitEnum|string $name + * @param \Closure $callback + * @return \Illuminate\Cache\RateLimiter + * @static + */ + public static function for($name, $callback) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->for($name, $callback); + } + + /** + * Get the given named rate limiter. + * + * @param \BackedEnum|\UnitEnum|string $name + * @return \Closure|null + * @static + */ + public static function limiter($name) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->limiter($name); + } + + /** + * Attempts to execute a callback if it's not limited. + * + * @param string $key + * @param int $maxAttempts + * @param \Closure $callback + * @param int $decaySeconds + * @return mixed + * @static + */ + public static function attempt($key, $maxAttempts, $callback, $decaySeconds = 60) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->attempt($key, $maxAttempts, $callback, $decaySeconds); + } + + /** + * Determine if the given key has been "accessed" too many times. + * + * @param string $key + * @param int $maxAttempts + * @return bool + * @static + */ + public static function tooManyAttempts($key, $maxAttempts) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->tooManyAttempts($key, $maxAttempts); + } + + /** + * Increment (by 1) the counter for a given key for a given decay time. + * + * @param string $key + * @param int $decaySeconds + * @return int + * @static + */ + public static function hit($key, $decaySeconds = 60) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->hit($key, $decaySeconds); + } + + /** + * Increment the counter for a given key for a given decay time by a given amount. + * + * @param string $key + * @param int $decaySeconds + * @param int $amount + * @return int + * @static + */ + public static function increment($key, $decaySeconds = 60, $amount = 1) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->increment($key, $decaySeconds, $amount); + } + + /** + * Decrement the counter for a given key for a given decay time by a given amount. + * + * @param string $key + * @param int $decaySeconds + * @param int $amount + * @return int + * @static + */ + public static function decrement($key, $decaySeconds = 60, $amount = 1) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->decrement($key, $decaySeconds, $amount); + } + + /** + * Get the number of attempts for the given key. + * + * @param string $key + * @return mixed + * @static + */ + public static function attempts($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->attempts($key); + } + + /** + * Reset the number of attempts for the given key. + * + * @param string $key + * @return mixed + * @static + */ + public static function resetAttempts($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->resetAttempts($key); + } + + /** + * Get the number of retries left for the given key. + * + * @param string $key + * @param int $maxAttempts + * @return int + * @static + */ + public static function remaining($key, $maxAttempts) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->remaining($key, $maxAttempts); + } + + /** + * Get the number of retries left for the given key. + * + * @param string $key + * @param int $maxAttempts + * @return int + * @static + */ + public static function retriesLeft($key, $maxAttempts) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->retriesLeft($key, $maxAttempts); + } + + /** + * Clear the hits and lockout timer for the given key. + * + * @param string $key + * @return void + * @static + */ + public static function clear($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + $instance->clear($key); + } + + /** + * Get the number of seconds until the "key" is accessible again. + * + * @param string $key + * @return int + * @static + */ + public static function availableIn($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->availableIn($key); + } + + /** + * Clean the rate limiter key from unicode characters. + * + * @param string $key + * @return string + * @static + */ + public static function cleanRateLimiterKey($key) + { + /** @var \Illuminate\Cache\RateLimiter $instance */ + return $instance->cleanRateLimiterKey($key); + } + + } + /** + * + * + * @see \Illuminate\Routing\Redirector + */ + class Redirect { + /** + * Create a new redirect response to the previous location. + * + * @param int $status + * @param array $headers + * @param mixed $fallback + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function back($status = 302, $headers = [], $fallback = false) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->back($status, $headers, $fallback); + } + + /** + * Create a new redirect response to the current URI. + * + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function refresh($status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->refresh($status, $headers); + } + + /** + * Create a new redirect response, while putting the current URL in the session. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function guest($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->guest($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to the previously intended location. + * + * @param mixed $default + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function intended($default = '/', $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->intended($default, $status, $headers, $secure); + } + + /** + * Create a new redirect response to the given path. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function to($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->to($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to an external URL (no validation). + * + * @param string $path + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function away($path, $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->away($path, $status, $headers); + } + + /** + * Create a new redirect response to the given HTTPS path. + * + * @param string $path + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function secure($path, $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->secure($path, $status, $headers); + } + + /** + * Create a new redirect response to a named route. + * + * @param \BackedEnum|string $route + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function route($route, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->route($route, $parameters, $status, $headers); + } + + /** + * Create a new redirect response to a signed named route. + * + * @param \BackedEnum|string $route + * @param mixed $parameters + * @param \DateTimeInterface|\DateInterval|int|null $expiration + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function signedRoute($route, $parameters = [], $expiration = null, $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->signedRoute($route, $parameters, $expiration, $status, $headers); + } + + /** + * Create a new redirect response to a signed named route. + * + * @param \BackedEnum|string $route + * @param \DateTimeInterface|\DateInterval|int|null $expiration + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function temporarySignedRoute($route, $expiration, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->temporarySignedRoute($route, $expiration, $parameters, $status, $headers); + } + + /** + * Create a new redirect response to a controller action. + * + * @param string|array $action + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function action($action, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->action($action, $parameters, $status, $headers); + } + + /** + * Get the URL generator instance. + * + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function getUrlGenerator() + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->getUrlGenerator(); + } + + /** + * Set the active session store. + * + * @param \Illuminate\Session\Store $session + * @return void + * @static + */ + public static function setSession($session) + { + /** @var \Illuminate\Routing\Redirector $instance */ + $instance->setSession($session); + } + + /** + * Get the "intended" URL from the session. + * + * @return string|null + * @static + */ + public static function getIntendedUrl() + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->getIntendedUrl(); + } + + /** + * Set the "intended" URL in the session. + * + * @param string $url + * @return \Illuminate\Routing\Redirector + * @static + */ + public static function setIntendedUrl($url) + { + /** @var \Illuminate\Routing\Redirector $instance */ + return $instance->setIntendedUrl($url); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\Redirector::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\Redirector::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\Redirector::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\Redirector::flushMacros(); + } + + } + /** + * + * + * @method static array|(\Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null file(string|null $key = null, mixed $default = null) + * @method static array validate(array $rules, ...$params) + * @method static array validateWithBag(string $errorBag, array $rules, ...$params) + * @method static bool hasValidSignature(bool $absolute = true) + * @see \Illuminate\Http\Request + */ + class Request { + /** + * Create a new Illuminate HTTP request from server variables. + * + * @return static + * @static + */ + public static function capture() + { + return \Illuminate\Http\Request::capture(); + } + + /** + * Return the Request instance. + * + * @return \Illuminate\Http\Request + * @static + */ + public static function instance() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->instance(); + } + + /** + * Get the request method. + * + * @return string + * @static + */ + public static function method() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->method(); + } + + /** + * Get a URI instance for the request. + * + * @return \Illuminate\Support\Uri + * @static + */ + public static function uri() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->uri(); + } + + /** + * Get the root URL for the application. + * + * @return string + * @static + */ + public static function root() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->root(); + } + + /** + * Get the URL (no query string) for the request. + * + * @return string + * @static + */ + public static function url() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->url(); + } + + /** + * Get the full URL for the request. + * + * @return string + * @static + */ + public static function fullUrl() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrl(); + } + + /** + * Get the full URL for the request with the added query string parameters. + * + * @param array $query + * @return string + * @static + */ + public static function fullUrlWithQuery($query) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrlWithQuery($query); + } + + /** + * Get the full URL for the request without the given query string parameters. + * + * @param array|string $keys + * @return string + * @static + */ + public static function fullUrlWithoutQuery($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrlWithoutQuery($keys); + } + + /** + * Get the current path info for the request. + * + * @return string + * @static + */ + public static function path() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->path(); + } + + /** + * Get the current decoded path info for the request. + * + * @return string + * @static + */ + public static function decodedPath() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->decodedPath(); + } + + /** + * Get a segment from the URI (1 based index). + * + * @param int $index + * @param string|null $default + * @return string|null + * @static + */ + public static function segment($index, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->segment($index, $default); + } + + /** + * Get all of the segments for the request path. + * + * @return array + * @static + */ + public static function segments() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->segments(); + } + + /** + * Determine if the current request URI matches a pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function is(...$patterns) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->is(...$patterns); + } + + /** + * Determine if the route name matches a given pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function routeIs(...$patterns) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->routeIs(...$patterns); + } + + /** + * Determine if the current request URL and query string match a pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function fullUrlIs(...$patterns) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fullUrlIs(...$patterns); + } + + /** + * Get the host name. + * + * @return string + * @static + */ + public static function host() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->host(); + } + + /** + * Get the HTTP host being requested. + * + * @return string + * @static + */ + public static function httpHost() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->httpHost(); + } + + /** + * Get the scheme and HTTP host. + * + * @return string + * @static + */ + public static function schemeAndHttpHost() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->schemeAndHttpHost(); + } + + /** + * Determine if the request is the result of an AJAX call. + * + * @return bool + * @static + */ + public static function ajax() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->ajax(); + } + + /** + * Determine if the request is the result of a PJAX call. + * + * @return bool + * @static + */ + public static function pjax() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->pjax(); + } + + /** + * Determine if the request is the result of a prefetch call. + * + * @return bool + * @static + */ + public static function prefetch() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->prefetch(); + } + + /** + * Determine if the request is over HTTPS. + * + * @return bool + * @static + */ + public static function secure() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->secure(); + } + + /** + * Get the client IP address. + * + * @return string|null + * @static + */ + public static function ip() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->ip(); + } + + /** + * Get the client IP addresses. + * + * @return array + * @static + */ + public static function ips() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->ips(); + } + + /** + * Get the client user agent. + * + * @return string|null + * @static + */ + public static function userAgent() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->userAgent(); + } + + /** + * Merge new input into the current request's input array. + * + * @param array $input + * @return \Illuminate\Http\Request + * @static + */ + public static function merge($input) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->merge($input); + } + + /** + * Merge new input into the request's input, but only when that key is missing from the request. + * + * @param array $input + * @return \Illuminate\Http\Request + * @static + */ + public static function mergeIfMissing($input) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->mergeIfMissing($input); + } + + /** + * Replace the input values for the current request. + * + * @param array $input + * @return \Illuminate\Http\Request + * @static + */ + public static function replace($input) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->replace($input); + } + + /** + * This method belongs to Symfony HttpFoundation and is not usually needed when using Laravel. + * + * Instead, you may use the "input" method. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->get($key, $default); + } + + /** + * Get the JSON payload for the request. + * + * @param string|null $key + * @param mixed $default + * @return \Symfony\Component\HttpFoundation\InputBag|mixed + * @static + */ + public static function json($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->json($key, $default); + } + + /** + * Create a new request instance from the given Laravel request. + * + * @param \Illuminate\Http\Request $from + * @param \Illuminate\Http\Request|null $to + * @return static + * @static + */ + public static function createFrom($from, $to = null) + { + return \Illuminate\Http\Request::createFrom($from, $to); + } + + /** + * Create an Illuminate request from a Symfony instance. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @return static + * @static + */ + public static function createFromBase($request) + { + return \Illuminate\Http\Request::createFromBase($request); + } + + /** + * Clones a request and overrides some of its parameters. + * + * @return static + * @param array|null $query The GET parameters + * @param array|null $request The POST parameters + * @param array|null $attributes The request attributes (parameters parsed from the PATH_INFO, ...) + * @param array|null $cookies The COOKIE parameters + * @param array|null $files The FILES parameters + * @param array|null $server The SERVER parameters + * @static + */ + public static function duplicate($query = null, $request = null, $attributes = null, $cookies = null, $files = null, $server = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->duplicate($query, $request, $attributes, $cookies, $files, $server); + } + + /** + * Whether the request contains a Session object. + * + * This method does not give any information about the state of the session object, + * like whether the session is started or not. It is just a way to check if this Request + * is associated with a Session instance. + * + * @param bool $skipIfUninitialized When true, ignores factories injected by `setSessionFactory` + * @static + */ + public static function hasSession($skipIfUninitialized = false) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasSession($skipIfUninitialized); + } + + /** + * Gets the Session. + * + * @throws SessionNotFoundException When session is not set properly + * @static + */ + public static function getSession() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->getSession(); + } + + /** + * Get the session associated with the request. + * + * @return \Illuminate\Contracts\Session\Session + * @throws \RuntimeException + * @static + */ + public static function session() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->session(); + } + + /** + * Set the session instance on the request. + * + * @param \Illuminate\Contracts\Session\Session $session + * @return void + * @static + */ + public static function setLaravelSession($session) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->setLaravelSession($session); + } + + /** + * Set the locale for the request instance. + * + * @param string $locale + * @return void + * @static + */ + public static function setRequestLocale($locale) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->setRequestLocale($locale); + } + + /** + * Set the default locale for the request instance. + * + * @param string $locale + * @return void + * @static + */ + public static function setDefaultRequestLocale($locale) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->setDefaultRequestLocale($locale); + } + + /** + * Get the user making the request. + * + * @param string|null $guard + * @return mixed + * @static + */ + public static function user($guard = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->user($guard); + } + + /** + * Get the route handling the request. + * + * @param string|null $param + * @param mixed $default + * @return \Illuminate\Routing\Route|object|string|null + * @static + */ + public static function route($param = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->route($param, $default); + } + + /** + * Get a unique fingerprint for the request / route / IP address. + * + * @return string + * @throws \RuntimeException + * @static + */ + public static function fingerprint() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fingerprint(); + } + + /** + * Set the JSON payload for the request. + * + * @param \Symfony\Component\HttpFoundation\InputBag $json + * @return \Illuminate\Http\Request + * @static + */ + public static function setJson($json) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->setJson($json); + } + + /** + * Get the user resolver callback. + * + * @return \Closure + * @static + */ + public static function getUserResolver() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUserResolver(); + } + + /** + * Set the user resolver callback. + * + * @param \Closure $callback + * @return \Illuminate\Http\Request + * @static + */ + public static function setUserResolver($callback) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->setUserResolver($callback); + } + + /** + * Get the route resolver callback. + * + * @return \Closure + * @static + */ + public static function getRouteResolver() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRouteResolver(); + } + + /** + * Set the route resolver callback. + * + * @param \Closure $callback + * @return \Illuminate\Http\Request + * @static + */ + public static function setRouteResolver($callback) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->setRouteResolver($callback); + } + + /** + * Get all of the input and files for the request. + * + * @return array + * @static + */ + public static function toArray() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->toArray(); + } + + /** + * Determine if the given offset exists. + * + * @param string $offset + * @return bool + * @static + */ + public static function offsetExists($offset) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->offsetExists($offset); + } + + /** + * Get the value at the given offset. + * + * @param string $offset + * @return mixed + * @static + */ + public static function offsetGet($offset) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->offsetGet($offset); + } + + /** + * Set the value at the given offset. + * + * @param string $offset + * @param mixed $value + * @return void + * @static + */ + public static function offsetSet($offset, $value) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->offsetSet($offset, $value); + } + + /** + * Remove the value at the given offset. + * + * @param string $offset + * @return void + * @static + */ + public static function offsetUnset($offset) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->offsetUnset($offset); + } + + /** + * Sets the parameters for this request. + * + * This method also re-initializes all properties. + * + * @param array $query The GET parameters + * @param array $request The POST parameters + * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) + * @param array $cookies The COOKIE parameters + * @param array $files The FILES parameters + * @param array $server The SERVER parameters + * @param string|resource|null $content The raw body data + * @static + */ + public static function initialize($query = [], $request = [], $attributes = [], $cookies = [], $files = [], $server = [], $content = null) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->initialize($query, $request, $attributes, $cookies, $files, $server, $content); + } + + /** + * Creates a new request with values from PHP's super globals. + * + * @static + */ + public static function createFromGlobals() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::createFromGlobals(); + } + + /** + * Creates a Request based on a given URI and configuration. + * + * The information contained in the URI always take precedence + * over the other information (server and parameters). + * + * @param string $uri The URI + * @param string $method The HTTP method + * @param array $parameters The query (GET) or request (POST) parameters + * @param array $cookies The request cookies ($_COOKIE) + * @param array $files The request files ($_FILES) + * @param array $server The server parameters ($_SERVER) + * @param string|resource|null $content The raw body data + * @throws BadRequestException When the URI is invalid + * @static + */ + public static function create($uri, $method = 'GET', $parameters = [], $cookies = [], $files = [], $server = [], $content = null) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::create($uri, $method, $parameters, $cookies, $files, $server, $content); + } + + /** + * Sets a callable able to create a Request instance. + * + * This is mainly useful when you need to override the Request class + * to keep BC with an existing system. It should not be used for any + * other purpose. + * + * @static + */ + public static function setFactory($callable) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::setFactory($callable); + } + + /** + * Overrides the PHP global variables according to this request instance. + * + * It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE. + * $_FILES is never overridden, see rfc1867 + * + * @static + */ + public static function overrideGlobals() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->overrideGlobals(); + } + + /** + * Sets a list of trusted proxies. + * + * You should only list the reverse proxies that you manage directly. + * + * @param array $proxies A list of trusted proxies, the string 'REMOTE_ADDR' will be replaced with $_SERVER['REMOTE_ADDR'] and 'PRIVATE_SUBNETS' by IpUtils::PRIVATE_SUBNETS + * @param int-mask-of $trustedHeaderSet A bit field to set which headers to trust from your proxies + * @static + */ + public static function setTrustedProxies($proxies, $trustedHeaderSet) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::setTrustedProxies($proxies, $trustedHeaderSet); + } + + /** + * Gets the list of trusted proxies. + * + * @return string[] + * @static + */ + public static function getTrustedProxies() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getTrustedProxies(); + } + + /** + * Gets the set of trusted headers from trusted proxies. + * + * @return int A bit field of Request::HEADER_* that defines which headers are trusted from your proxies + * @static + */ + public static function getTrustedHeaderSet() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getTrustedHeaderSet(); + } + + /** + * Sets a list of trusted host patterns. + * + * You should only list the hosts you manage using regexs. + * + * @param array $hostPatterns A list of trusted host patterns + * @static + */ + public static function setTrustedHosts($hostPatterns) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::setTrustedHosts($hostPatterns); + } + + /** + * Gets the list of trusted host patterns. + * + * @return string[] + * @static + */ + public static function getTrustedHosts() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getTrustedHosts(); + } + + /** + * Normalizes a query string. + * + * It builds a normalized query string, where keys/value pairs are alphabetized, + * have consistent escaping and unneeded delimiters are removed. + * + * @static + */ + public static function normalizeQueryString($qs) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::normalizeQueryString($qs); + } + + /** + * Enables support for the _method request parameter to determine the intended HTTP method. + * + * Be warned that enabling this feature might lead to CSRF issues in your code. + * Check that you are using CSRF tokens when required. + * If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered + * and used to send a "PUT" or "DELETE" request via the _method request parameter. + * If these methods are not protected against CSRF, this presents a possible vulnerability. + * + * The HTTP method can only be overridden when the real HTTP method is POST. + * + * @static + */ + public static function enableHttpMethodParameterOverride() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::enableHttpMethodParameterOverride(); + } + + /** + * Checks whether support for the _method request parameter is enabled. + * + * @static + */ + public static function getHttpMethodParameterOverride() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getHttpMethodParameterOverride(); + } + + /** + * Whether the request contains a Session which was started in one of the + * previous requests. + * + * @static + */ + public static function hasPreviousSession() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasPreviousSession(); + } + + /** + * + * + * @static + */ + public static function setSession($session) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setSession($session); + } + + /** + * + * + * @internal + * @param callable(): SessionInterface $factory + * @static + */ + public static function setSessionFactory($factory) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setSessionFactory($factory); + } + + /** + * Returns the client IP addresses. + * + * In the returned array the most trusted IP address is first, and the + * least trusted one last. The "real" client IP address is the last one, + * but this is also the least trusted one. Trusted proxies are stripped. + * + * Use this method carefully; you should use getClientIp() instead. + * + * @see getClientIp() + * @static + */ + public static function getClientIps() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getClientIps(); + } + + /** + * Returns the client IP address. + * + * This method can read the client IP address from the "X-Forwarded-For" header + * when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For" + * header value is a comma+space separated list of IP addresses, the left-most + * being the original client, and each successive proxy that passed the request + * adding the IP address where it received the request from. + * + * If your reverse proxy uses a different header name than "X-Forwarded-For", + * ("Client-Ip" for instance), configure it via the $trustedHeaderSet + * argument of the Request::setTrustedProxies() method instead. + * + * @see getClientIps() + * @see https://wikipedia.org/wiki/X-Forwarded-For + * @static + */ + public static function getClientIp() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getClientIp(); + } + + /** + * Returns current script name. + * + * @static + */ + public static function getScriptName() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getScriptName(); + } + + /** + * Returns the path being requested relative to the executed script. + * + * The path info always starts with a /. + * + * Suppose this request is instantiated from /mysite on localhost: + * + * * http://localhost/mysite returns an empty string + * * http://localhost/mysite/about returns '/about' + * * http://localhost/mysite/enco%20ded returns '/enco%20ded' + * * http://localhost/mysite/about?var=1 returns '/about' + * + * @return string The raw path (i.e. not urldecoded) + * @static + */ + public static function getPathInfo() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPathInfo(); + } + + /** + * Returns the root path from which this request is executed. + * + * Suppose that an index.php file instantiates this request object: + * + * * http://localhost/index.php returns an empty string + * * http://localhost/index.php/page returns an empty string + * * http://localhost/web/index.php returns '/web' + * * http://localhost/we%20b/index.php returns '/we%20b' + * + * @return string The raw path (i.e. not urldecoded) + * @static + */ + public static function getBasePath() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getBasePath(); + } + + /** + * Returns the root URL from which this request is executed. + * + * The base URL never ends with a /. + * + * This is similar to getBasePath(), except that it also includes the + * script filename (e.g. index.php) if one exists. + * + * @return string The raw URL (i.e. not urldecoded) + * @static + */ + public static function getBaseUrl() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getBaseUrl(); + } + + /** + * Gets the request's scheme. + * + * @static + */ + public static function getScheme() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getScheme(); + } + + /** + * Returns the port on which the request is made. + * + * This method can read the client port from the "X-Forwarded-Port" header + * when trusted proxies were set via "setTrustedProxies()". + * + * The "X-Forwarded-Port" header must contain the client port. + * + * @return int|string|null Can be a string if fetched from the server bag + * @static + */ + public static function getPort() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPort(); + } + + /** + * Returns the user. + * + * @static + */ + public static function getUser() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUser(); + } + + /** + * Returns the password. + * + * @static + */ + public static function getPassword() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPassword(); + } + + /** + * Gets the user info. + * + * @return string|null A user name if any and, optionally, scheme-specific information about how to gain authorization to access the server + * @static + */ + public static function getUserInfo() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUserInfo(); + } + + /** + * Returns the HTTP host being requested. + * + * The port name will be appended to the host if it's non-standard. + * + * @static + */ + public static function getHttpHost() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getHttpHost(); + } + + /** + * Returns the requested URI (path and query string). + * + * @return string The raw URI (i.e. not URI decoded) + * @static + */ + public static function getRequestUri() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRequestUri(); + } + + /** + * Gets the scheme and HTTP host. + * + * If the URL was called with basic authentication, the user + * and the password are not added to the generated string. + * + * @static + */ + public static function getSchemeAndHttpHost() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getSchemeAndHttpHost(); + } + + /** + * Generates a normalized URI (URL) for the Request. + * + * @see getQueryString() + * @static + */ + public static function getUri() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUri(); + } + + /** + * Generates a normalized URI for the given path. + * + * @param string $path A path to use instead of the current one + * @static + */ + public static function getUriForPath($path) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getUriForPath($path); + } + + /** + * Returns the path as relative reference from the current Request path. + * + * Only the URIs path component (no schema, host etc.) is relevant and must be given. + * Both paths must be absolute and not contain relative parts. + * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives. + * Furthermore, they can be used to reduce the link size in documents. + * + * Example target paths, given a base path of "/a/b/c/d": + * - "/a/b/c/d" -> "" + * - "/a/b/c/" -> "./" + * - "/a/b/" -> "../" + * - "/a/b/c/other" -> "other" + * - "/a/x/y" -> "../../x/y" + * + * @static + */ + public static function getRelativeUriForPath($path) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRelativeUriForPath($path); + } + + /** + * Generates the normalized query string for the Request. + * + * It builds a normalized query string, where keys/value pairs are alphabetized + * and have consistent escaping. + * + * @static + */ + public static function getQueryString() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getQueryString(); + } + + /** + * Checks whether the request is secure or not. + * + * This method can read the client protocol from the "X-Forwarded-Proto" header + * when trusted proxies were set via "setTrustedProxies()". + * + * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http". + * + * @static + */ + public static function isSecure() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isSecure(); + } + + /** + * Returns the host name. + * + * This method can read the client host name from the "X-Forwarded-Host" header + * when trusted proxies were set via "setTrustedProxies()". + * + * The "X-Forwarded-Host" header must contain the client host name. + * + * @throws SuspiciousOperationException when the host name is invalid or not trusted + * @static + */ + public static function getHost() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getHost(); + } + + /** + * Sets the request method. + * + * @static + */ + public static function setMethod($method) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setMethod($method); + } + + /** + * Gets the request "intended" method. + * + * If the X-HTTP-Method-Override header is set, and if the method is a POST, + * then it is used to determine the "real" intended HTTP method. + * + * The _method request parameter can also be used to determine the HTTP method, + * but only if enableHttpMethodParameterOverride() has been called. + * + * The method is always an uppercased string. + * + * @see getRealMethod() + * @static + */ + public static function getMethod() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getMethod(); + } + + /** + * Gets the "real" request method. + * + * @see getMethod() + * @static + */ + public static function getRealMethod() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRealMethod(); + } + + /** + * Gets the mime type associated with the format. + * + * @static + */ + public static function getMimeType($format) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getMimeType($format); + } + + /** + * Gets the mime types associated with the format. + * + * @return string[] + * @static + */ + public static function getMimeTypes($format) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + return \Illuminate\Http\Request::getMimeTypes($format); + } + + /** + * Gets the format associated with the mime type. + * + * @static + */ + public static function getFormat($mimeType) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getFormat($mimeType); + } + + /** + * Associates a format with mime types. + * + * @param string|string[] $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type) + * @static + */ + public static function setFormat($format, $mimeTypes) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setFormat($format, $mimeTypes); + } + + /** + * Gets the request format. + * + * Here is the process to determine the format: + * + * * format defined by the user (with setRequestFormat()) + * * _format request attribute + * * $default + * + * @see getPreferredFormat + * @static + */ + public static function getRequestFormat($default = 'html') + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getRequestFormat($default); + } + + /** + * Sets the request format. + * + * @static + */ + public static function setRequestFormat($format) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setRequestFormat($format); + } + + /** + * Gets the usual name of the format associated with the request's media type (provided in the Content-Type header). + * + * @see Request::$formats + * @static + */ + public static function getContentTypeFormat() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getContentTypeFormat(); + } + + /** + * Sets the default locale. + * + * @static + */ + public static function setDefaultLocale($locale) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setDefaultLocale($locale); + } + + /** + * Get the default locale. + * + * @static + */ + public static function getDefaultLocale() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getDefaultLocale(); + } + + /** + * Sets the locale. + * + * @static + */ + public static function setLocale($locale) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->setLocale($locale); + } + + /** + * Get the locale. + * + * @static + */ + public static function getLocale() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getLocale(); + } + + /** + * Checks if the request method is of specified type. + * + * @param string $method Uppercase request method (GET, POST etc) + * @static + */ + public static function isMethod($method) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethod($method); + } + + /** + * Checks whether or not the method is safe. + * + * @see https://tools.ietf.org/html/rfc7231#section-4.2.1 + * @static + */ + public static function isMethodSafe() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethodSafe(); + } + + /** + * Checks whether or not the method is idempotent. + * + * @static + */ + public static function isMethodIdempotent() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethodIdempotent(); + } + + /** + * Checks whether the method is cacheable or not. + * + * @see https://tools.ietf.org/html/rfc7231#section-4.2.3 + * @static + */ + public static function isMethodCacheable() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isMethodCacheable(); + } + + /** + * Returns the protocol version. + * + * If the application is behind a proxy, the protocol version used in the + * requests between the client and the proxy and between the proxy and the + * server might be different. This returns the former (from the "Via" header) + * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns + * the latter (from the "SERVER_PROTOCOL" server parameter). + * + * @static + */ + public static function getProtocolVersion() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getProtocolVersion(); + } + + /** + * Returns the request body content. + * + * @param bool $asResource If true, a resource will be returned + * @return string|resource + * @psalm-return ($asResource is true ? resource : string) + * @static + */ + public static function getContent($asResource = false) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getContent($asResource); + } + + /** + * Gets the decoded form or json request body. + * + * @throws JsonException When the body cannot be decoded to an array + * @static + */ + public static function getPayload() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPayload(); + } + + /** + * Gets the Etags. + * + * @static + */ + public static function getETags() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getETags(); + } + + /** + * + * + * @static + */ + public static function isNoCache() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isNoCache(); + } + + /** + * Gets the preferred format for the response by inspecting, in the following order: + * * the request format set using setRequestFormat; + * * the values of the Accept HTTP header. + * + * Note that if you use this method, you should send the "Vary: Accept" header + * in the response to prevent any issues with intermediary HTTP caches. + * + * @static + */ + public static function getPreferredFormat($default = 'html') + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPreferredFormat($default); + } + + /** + * Returns the preferred language. + * + * @param string[] $locales An array of ordered available locales + * @static + */ + public static function getPreferredLanguage($locales = null) + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getPreferredLanguage($locales); + } + + /** + * Gets a list of languages acceptable by the client browser ordered in the user browser preferences. + * + * @return string[] + * @static + */ + public static function getLanguages() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getLanguages(); + } + + /** + * Gets a list of charsets acceptable by the client browser in preferable order. + * + * @return string[] + * @static + */ + public static function getCharsets() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getCharsets(); + } + + /** + * Gets a list of encodings acceptable by the client browser in preferable order. + * + * @return string[] + * @static + */ + public static function getEncodings() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getEncodings(); + } + + /** + * Gets a list of content types acceptable by the client browser in preferable order. + * + * @return string[] + * @static + */ + public static function getAcceptableContentTypes() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->getAcceptableContentTypes(); + } + + /** + * Returns true if the request is an XMLHttpRequest. + * + * It works if your JavaScript library sets an X-Requested-With HTTP header. + * It is known to work with common JavaScript frameworks: + * + * @see https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript + * @static + */ + public static function isXmlHttpRequest() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isXmlHttpRequest(); + } + + /** + * Checks whether the client browser prefers safe content or not according to RFC8674. + * + * @see https://tools.ietf.org/html/rfc8674 + * @static + */ + public static function preferSafeContent() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->preferSafeContent(); + } + + /** + * Indicates whether this request originated from a trusted proxy. + * + * This can be useful to determine whether or not to trust the + * contents of a proxy-specific header. + * + * @static + */ + public static function isFromTrustedProxy() + { + //Method inherited from \Symfony\Component\HttpFoundation\Request + /** @var \Illuminate\Http\Request $instance */ + return $instance->isFromTrustedProxy(); + } + + /** + * Filter the given array of rules into an array of rules that are included in precognitive headers. + * + * @param array $rules + * @return array + * @static + */ + public static function filterPrecognitiveRules($rules) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->filterPrecognitiveRules($rules); + } + + /** + * Determine if the request is attempting to be precognitive. + * + * @return bool + * @static + */ + public static function isAttemptingPrecognition() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isAttemptingPrecognition(); + } + + /** + * Determine if the request is precognitive. + * + * @return bool + * @static + */ + public static function isPrecognitive() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isPrecognitive(); + } + + /** + * Determine if the request is sending JSON. + * + * @return bool + * @static + */ + public static function isJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isJson(); + } + + /** + * Determine if the current request probably expects a JSON response. + * + * @return bool + * @static + */ + public static function expectsJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->expectsJson(); + } + + /** + * Determine if the current request is asking for JSON. + * + * @return bool + * @static + */ + public static function wantsJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->wantsJson(); + } + + /** + * Determines whether the current requests accepts a given content type. + * + * @param string|array $contentTypes + * @return bool + * @static + */ + public static function accepts($contentTypes) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->accepts($contentTypes); + } + + /** + * Return the most suitable content type from the given array based on content negotiation. + * + * @param string|array $contentTypes + * @return string|null + * @static + */ + public static function prefers($contentTypes) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->prefers($contentTypes); + } + + /** + * Determine if the current request accepts any content type. + * + * @return bool + * @static + */ + public static function acceptsAnyContentType() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->acceptsAnyContentType(); + } + + /** + * Determines whether a request accepts JSON. + * + * @return bool + * @static + */ + public static function acceptsJson() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->acceptsJson(); + } + + /** + * Determines whether a request accepts HTML. + * + * @return bool + * @static + */ + public static function acceptsHtml() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->acceptsHtml(); + } + + /** + * Determine if the given content types match. + * + * @param string $actual + * @param string $type + * @return bool + * @static + */ + public static function matchesType($actual, $type) + { + return \Illuminate\Http\Request::matchesType($actual, $type); + } + + /** + * Get the data format expected in the response. + * + * @param string $default + * @return string + * @static + */ + public static function format($default = 'html') + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->format($default); + } + + /** + * Retrieve an old input item. + * + * @param string|null $key + * @param \Illuminate\Database\Eloquent\Model|string|array|null $default + * @return string|array|null + * @static + */ + public static function old($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->old($key, $default); + } + + /** + * Flash the input for the current request to the session. + * + * @return void + * @static + */ + public static function flash() + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flash(); + } + + /** + * Flash only some of the input to the session. + * + * @param array|mixed $keys + * @return void + * @static + */ + public static function flashOnly($keys) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flashOnly($keys); + } + + /** + * Flash only some of the input to the session. + * + * @param array|mixed $keys + * @return void + * @static + */ + public static function flashExcept($keys) + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flashExcept($keys); + } + + /** + * Flush all of the old input from the session. + * + * @return void + * @static + */ + public static function flush() + { + /** @var \Illuminate\Http\Request $instance */ + $instance->flush(); + } + + /** + * Retrieve a server variable from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function server($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->server($key, $default); + } + + /** + * Determine if a header is set on the request. + * + * @param string $key + * @return bool + * @static + */ + public static function hasHeader($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasHeader($key); + } + + /** + * Retrieve a header from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function header($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->header($key, $default); + } + + /** + * Get the bearer token from the request headers. + * + * @return string|null + * @static + */ + public static function bearerToken() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->bearerToken(); + } + + /** + * Get the keys for all of the input and files. + * + * @return array + * @static + */ + public static function keys() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->keys(); + } + + /** + * Get all of the input and files for the request. + * + * @param array|mixed|null $keys + * @return array + * @static + */ + public static function all($keys = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->all($keys); + } + + /** + * Retrieve an input item from the request. + * + * @param string|null $key + * @param mixed $default + * @return mixed + * @static + */ + public static function input($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->input($key, $default); + } + + /** + * Retrieve input from the request as a Fluent object instance. + * + * @param array|string|null $key + * @return \Illuminate\Support\Fluent + * @static + */ + public static function fluent($key = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->fluent($key); + } + + /** + * Retrieve a query string item from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function query($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->query($key, $default); + } + + /** + * Retrieve a request payload item from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function post($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->post($key, $default); + } + + /** + * Determine if a cookie is set on the request. + * + * @param string $key + * @return bool + * @static + */ + public static function hasCookie($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasCookie($key); + } + + /** + * Retrieve a cookie from the request. + * + * @param string|null $key + * @param string|array|null $default + * @return string|array|null + * @static + */ + public static function cookie($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->cookie($key, $default); + } + + /** + * Get an array of all of the files on the request. + * + * @return array + * @static + */ + public static function allFiles() + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->allFiles(); + } + + /** + * Determine if the uploaded data contains a file. + * + * @param string $key + * @return bool + * @static + */ + public static function hasFile($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasFile($key); + } + + /** + * Retrieve a file from the request. + * + * @param string|null $key + * @param mixed $default + * @return ($key is null ? array : \Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null) + * @static + */ + public static function file($key = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->file($key, $default); + } + + /** + * Dump the items. + * + * @param mixed $keys + * @return \Illuminate\Http\Request + * @static + */ + public static function dump($keys = []) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->dump($keys); + } + + /** + * Dump the given arguments and terminate execution. + * + * @param mixed $args + * @return never + * @static + */ + public static function dd(...$args) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->dd(...$args); + } + + /** + * Determine if the data contains a given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function exists($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->exists($key); + } + + /** + * Determine if the data contains a given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->has($key); + } + + /** + * Determine if the instance contains any of the given keys. + * + * @param string|array $keys + * @return bool + * @static + */ + public static function hasAny($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->hasAny($keys); + } + + /** + * Apply the callback if the instance contains the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + * @static + */ + public static function whenHas($key, $callback, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->whenHas($key, $callback, $default); + } + + /** + * Determine if the instance contains a non-empty value for the given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function filled($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->filled($key); + } + + /** + * Determine if the instance contains an empty value for the given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function isNotFilled($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->isNotFilled($key); + } + + /** + * Determine if the instance contains a non-empty value for any of the given keys. + * + * @param string|array $keys + * @return bool + * @static + */ + public static function anyFilled($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->anyFilled($keys); + } + + /** + * Apply the callback if the instance contains a non-empty value for the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + * @static + */ + public static function whenFilled($key, $callback, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->whenFilled($key, $callback, $default); + } + + /** + * Determine if the instance is missing a given key. + * + * @param string|array $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->missing($key); + } + + /** + * Apply the callback if the instance is missing the given key. + * + * @param string $key + * @param callable $callback + * @param callable|null $default + * @return $this|mixed + * @static + */ + public static function whenMissing($key, $callback, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->whenMissing($key, $callback, $default); + } + + /** + * Retrieve data from the instance as a Stringable instance. + * + * @param string $key + * @param mixed $default + * @return \Illuminate\Support\Stringable + * @static + */ + public static function str($key, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->str($key, $default); + } + + /** + * Retrieve data from the instance as a Stringable instance. + * + * @param string $key + * @param mixed $default + * @return \Illuminate\Support\Stringable + * @static + */ + public static function string($key, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->string($key, $default); + } + + /** + * Retrieve data as a boolean value. + * + * Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false. + * + * @param string|null $key + * @param bool $default + * @return bool + * @static + */ + public static function boolean($key = null, $default = false) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->boolean($key, $default); + } + + /** + * Retrieve data as an integer value. + * + * @param string $key + * @param int $default + * @return int + * @static + */ + public static function integer($key, $default = 0) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->integer($key, $default); + } + + /** + * Retrieve data as a float value. + * + * @param string $key + * @param float $default + * @return float + * @static + */ + public static function float($key, $default = 0.0) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->float($key, $default); + } + + /** + * Retrieve data from the instance as a Carbon instance. + * + * @param string $key + * @param string|null $format + * @param string|null $tz + * @return \Illuminate\Support\Carbon|null + * @throws \Carbon\Exceptions\InvalidFormatException + * @static + */ + public static function date($key, $format = null, $tz = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->date($key, $format, $tz); + } + + /** + * Retrieve data from the instance as an enum. + * + * @template TEnum of \BackedEnum + * @param string $key + * @param class-string $enumClass + * @return TEnum|null + * @static + */ + public static function enum($key, $enumClass) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->enum($key, $enumClass); + } + + /** + * Retrieve data from the instance as an array of enums. + * + * @template TEnum of \BackedEnum + * @param string $key + * @param class-string $enumClass + * @return TEnum[] + * @static + */ + public static function enums($key, $enumClass) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->enums($key, $enumClass); + } + + /** + * Retrieve data from the instance as an array. + * + * @param array|string|null $key + * @return array + * @static + */ + public static function array($key = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->array($key); + } + + /** + * Retrieve data from the instance as a collection. + * + * @param array|string|null $key + * @return \Illuminate\Support\Collection + * @static + */ + public static function collect($key = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->collect($key); + } + + /** + * Get a subset containing the provided keys with values from the instance data. + * + * @param array|mixed $keys + * @return array + * @static + */ + public static function only($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->only($keys); + } + + /** + * Get all of the data except for a specified array of items. + * + * @param array|mixed $keys + * @return array + * @static + */ + public static function except($keys) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->except($keys); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Http\Request $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Http\Request::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Http\Request::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Http\Request::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Http\Request::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Routing\ResponseFactory + */ + class Response { + /** + * Create a new response instance. + * + * @param mixed $content + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + * @static + */ + public static function make($content = '', $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->make($content, $status, $headers); + } + + /** + * Create a new "no content" response. + * + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + * @static + */ + public static function noContent($status = 204, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->noContent($status, $headers); + } + + /** + * Create a new response for a given view. + * + * @param string|array $view + * @param array $data + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + * @static + */ + public static function view($view, $data = [], $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->view($view, $data, $status, $headers); + } + + /** + * Create a new JSON response instance. + * + * @param mixed $data + * @param int $status + * @param array $headers + * @param int $options + * @return \Illuminate\Http\JsonResponse + * @static + */ + public static function json($data = [], $status = 200, $headers = [], $options = 0) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->json($data, $status, $headers, $options); + } + + /** + * Create a new JSONP response instance. + * + * @param string $callback + * @param mixed $data + * @param int $status + * @param array $headers + * @param int $options + * @return \Illuminate\Http\JsonResponse + * @static + */ + public static function jsonp($callback, $data = [], $status = 200, $headers = [], $options = 0) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->jsonp($callback, $data, $status, $headers, $options); + } + + /** + * Create a new event stream response. + * + * @param \Closure $callback + * @param array $headers + * @param \Illuminate\Http\StreamedEvent|string|null $endStreamWith + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function eventStream($callback, $headers = [], $endStreamWith = '') + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->eventStream($callback, $headers, $endStreamWith); + } + + /** + * Create a new streamed response instance. + * + * @param callable $callback + * @param int $status + * @param array $headers + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function stream($callback, $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->stream($callback, $status, $headers); + } + + /** + * Create a new streamed JSON response instance. + * + * @param array $data + * @param int $status + * @param array $headers + * @param int $encodingOptions + * @return \Symfony\Component\HttpFoundation\StreamedJsonResponse + * @static + */ + public static function streamJson($data, $status = 200, $headers = [], $encodingOptions = 15) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->streamJson($data, $status, $headers, $encodingOptions); + } + + /** + * Create a new streamed response instance as a file download. + * + * @param callable $callback + * @param string|null $name + * @param array $headers + * @param string|null $disposition + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @throws \Illuminate\Routing\Exceptions\StreamedResponseException + * @static + */ + public static function streamDownload($callback, $name = null, $headers = [], $disposition = 'attachment') + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->streamDownload($callback, $name, $headers, $disposition); + } + + /** + * Create a new file download response. + * + * @param \SplFileInfo|string $file + * @param string|null $name + * @param array $headers + * @param string|null $disposition + * @return \Symfony\Component\HttpFoundation\BinaryFileResponse + * @static + */ + public static function download($file, $name = null, $headers = [], $disposition = 'attachment') + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->download($file, $name, $headers, $disposition); + } + + /** + * Return the raw contents of a binary file. + * + * @param \SplFileInfo|string $file + * @param array $headers + * @return \Symfony\Component\HttpFoundation\BinaryFileResponse + * @static + */ + public static function file($file, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->file($file, $headers); + } + + /** + * Create a new redirect response to the given path. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectTo($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectTo($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to a named route. + * + * @param \BackedEnum|string $route + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectToRoute($route, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectToRoute($route, $parameters, $status, $headers); + } + + /** + * Create a new redirect response to a controller action. + * + * @param array|string $action + * @param mixed $parameters + * @param int $status + * @param array $headers + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectToAction($action, $parameters = [], $status = 302, $headers = []) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectToAction($action, $parameters, $status, $headers); + } + + /** + * Create a new redirect response, while putting the current URL in the session. + * + * @param string $path + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectGuest($path, $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectGuest($path, $status, $headers, $secure); + } + + /** + * Create a new redirect response to the previously intended location. + * + * @param string $default + * @param int $status + * @param array $headers + * @param bool|null $secure + * @return \Illuminate\Http\RedirectResponse + * @static + */ + public static function redirectToIntended($default = '/', $status = 302, $headers = [], $secure = null) + { + /** @var \Illuminate\Routing\ResponseFactory $instance */ + return $instance->redirectToIntended($default, $status, $headers, $secure); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\ResponseFactory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\ResponseFactory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\ResponseFactory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\ResponseFactory::flushMacros(); + } + + } + /** + * + * + * @method static \Illuminate\Routing\RouteRegistrar attribute(string $key, mixed $value) + * @method static \Illuminate\Routing\RouteRegistrar whereAlpha(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereAlphaNumeric(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereNumber(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereUlid(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereUuid(array|string $parameters) + * @method static \Illuminate\Routing\RouteRegistrar whereIn(array|string $parameters, array $values) + * @method static \Illuminate\Routing\RouteRegistrar as(string $value) + * @method static \Illuminate\Routing\RouteRegistrar can(\UnitEnum|string $ability, array|string $models = []) + * @method static \Illuminate\Routing\RouteRegistrar controller(string $controller) + * @method static \Illuminate\Routing\RouteRegistrar domain(\BackedEnum|string $value) + * @method static \Illuminate\Routing\RouteRegistrar middleware(array|string|null $middleware) + * @method static \Illuminate\Routing\RouteRegistrar missing(\Closure $missing) + * @method static \Illuminate\Routing\RouteRegistrar name(\BackedEnum|string $value) + * @method static \Illuminate\Routing\RouteRegistrar namespace(string|null $value) + * @method static \Illuminate\Routing\RouteRegistrar prefix(string $prefix) + * @method static \Illuminate\Routing\RouteRegistrar scopeBindings() + * @method static \Illuminate\Routing\RouteRegistrar where(array $where) + * @method static \Illuminate\Routing\RouteRegistrar withoutMiddleware(array|string $middleware) + * @method static \Illuminate\Routing\RouteRegistrar withoutScopedBindings() + * @see \Illuminate\Routing\Router + */ + class Route { + /** + * Register a new GET route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function get($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->get($uri, $action); + } + + /** + * Register a new POST route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function post($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->post($uri, $action); + } + + /** + * Register a new PUT route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function put($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->put($uri, $action); + } + + /** + * Register a new PATCH route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function patch($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->patch($uri, $action); + } + + /** + * Register a new DELETE route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function delete($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->delete($uri, $action); + } + + /** + * Register a new OPTIONS route with the router. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function options($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->options($uri, $action); + } + + /** + * Register a new route responding to all verbs. + * + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function any($uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->any($uri, $action); + } + + /** + * Register a new fallback route with the router. + * + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function fallback($action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->fallback($action); + } + + /** + * Create a redirect from one URI to another. + * + * @param string $uri + * @param string $destination + * @param int $status + * @return \Illuminate\Routing\Route + * @static + */ + public static function redirect($uri, $destination, $status = 302) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->redirect($uri, $destination, $status); + } + + /** + * Create a permanent redirect from one URI to another. + * + * @param string $uri + * @param string $destination + * @return \Illuminate\Routing\Route + * @static + */ + public static function permanentRedirect($uri, $destination) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->permanentRedirect($uri, $destination); + } + + /** + * Register a new route that returns a view. + * + * @param string $uri + * @param string $view + * @param array $data + * @param int|array $status + * @param array $headers + * @return \Illuminate\Routing\Route + * @static + */ + public static function view($uri, $view, $data = [], $status = 200, $headers = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->view($uri, $view, $data, $status, $headers); + } + + /** + * Register a new route with the given verbs. + * + * @param array|string $methods + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function match($methods, $uri, $action = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->match($methods, $uri, $action); + } + + /** + * Register an array of resource controllers. + * + * @param array $resources + * @param array $options + * @return void + * @static + */ + public static function resources($resources, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->resources($resources, $options); + } + + /** + * Route a resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingResourceRegistration + * @static + */ + public static function resource($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->resource($name, $controller, $options); + } + + /** + * Register an array of API resource controllers. + * + * @param array $resources + * @param array $options + * @return void + * @static + */ + public static function apiResources($resources, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->apiResources($resources, $options); + } + + /** + * Route an API resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingResourceRegistration + * @static + */ + public static function apiResource($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->apiResource($name, $controller, $options); + } + + /** + * Register an array of singleton resource controllers. + * + * @param array $singletons + * @param array $options + * @return void + * @static + */ + public static function singletons($singletons, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->singletons($singletons, $options); + } + + /** + * Route a singleton resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingSingletonResourceRegistration + * @static + */ + public static function singleton($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->singleton($name, $controller, $options); + } + + /** + * Register an array of API singleton resource controllers. + * + * @param array $singletons + * @param array $options + * @return void + * @static + */ + public static function apiSingletons($singletons, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->apiSingletons($singletons, $options); + } + + /** + * Route an API singleton resource to a controller. + * + * @param string $name + * @param string $controller + * @param array $options + * @return \Illuminate\Routing\PendingSingletonResourceRegistration + * @static + */ + public static function apiSingleton($name, $controller, $options = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->apiSingleton($name, $controller, $options); + } + + /** + * Create a route group with shared attributes. + * + * @param array $attributes + * @param \Closure|array|string $routes + * @return \Illuminate\Routing\Router + * @static + */ + public static function group($attributes, $routes) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->group($attributes, $routes); + } + + /** + * Merge the given array with the last group stack. + * + * @param array $new + * @param bool $prependExistingPrefix + * @return array + * @static + */ + public static function mergeWithLastGroup($new, $prependExistingPrefix = true) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->mergeWithLastGroup($new, $prependExistingPrefix); + } + + /** + * Get the prefix from the last group on the stack. + * + * @return string + * @static + */ + public static function getLastGroupPrefix() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getLastGroupPrefix(); + } + + /** + * Add a route to the underlying route collection. + * + * @param array|string $methods + * @param string $uri + * @param array|string|callable|null $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function addRoute($methods, $uri, $action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->addRoute($methods, $uri, $action); + } + + /** + * Create a new Route object. + * + * @param array|string $methods + * @param string $uri + * @param mixed $action + * @return \Illuminate\Routing\Route + * @static + */ + public static function newRoute($methods, $uri, $action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->newRoute($methods, $uri, $action); + } + + /** + * Return the response returned by the given route. + * + * @param string $name + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function respondWithRoute($name) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->respondWithRoute($name); + } + + /** + * Dispatch the request to the application. + * + * @param \Illuminate\Http\Request $request + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function dispatch($request) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->dispatch($request); + } + + /** + * Dispatch the request to a route and return the response. + * + * @param \Illuminate\Http\Request $request + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function dispatchToRoute($request) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->dispatchToRoute($request); + } + + /** + * Gather the middleware for the given route with resolved class names. + * + * @param \Illuminate\Routing\Route $route + * @return array + * @static + */ + public static function gatherRouteMiddleware($route) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->gatherRouteMiddleware($route); + } + + /** + * Resolve a flat array of middleware classes from the provided array. + * + * @param array $middleware + * @param array $excluded + * @return array + * @static + */ + public static function resolveMiddleware($middleware, $excluded = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->resolveMiddleware($middleware, $excluded); + } + + /** + * Create a response instance from the given value. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @param mixed $response + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function prepareResponse($request, $response) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->prepareResponse($request, $response); + } + + /** + * Static version of prepareResponse. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @param mixed $response + * @return \Symfony\Component\HttpFoundation\Response + * @static + */ + public static function toResponse($request, $response) + { + return \Illuminate\Routing\Router::toResponse($request, $response); + } + + /** + * Substitute the route bindings onto the route. + * + * @param \Illuminate\Routing\Route $route + * @return \Illuminate\Routing\Route + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException<\Illuminate\Database\Eloquent\Model> + * @throws \Illuminate\Routing\Exceptions\BackedEnumCaseNotFoundException + * @static + */ + public static function substituteBindings($route) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->substituteBindings($route); + } + + /** + * Substitute the implicit route bindings for the given route. + * + * @param \Illuminate\Routing\Route $route + * @return void + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException<\Illuminate\Database\Eloquent\Model> + * @throws \Illuminate\Routing\Exceptions\BackedEnumCaseNotFoundException + * @static + */ + public static function substituteImplicitBindings($route) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->substituteImplicitBindings($route); + } + + /** + * Register a callback to run after implicit bindings are substituted. + * + * @param callable $callback + * @return \Illuminate\Routing\Router + * @static + */ + public static function substituteImplicitBindingsUsing($callback) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->substituteImplicitBindingsUsing($callback); + } + + /** + * Register a route matched event listener. + * + * @param string|callable $callback + * @return void + * @static + */ + public static function matched($callback) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->matched($callback); + } + + /** + * Get all of the defined middleware short-hand names. + * + * @return array + * @static + */ + public static function getMiddleware() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getMiddleware(); + } + + /** + * Register a short-hand name for a middleware. + * + * @param string $name + * @param string $class + * @return \Illuminate\Routing\Router + * @static + */ + public static function aliasMiddleware($name, $class) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->aliasMiddleware($name, $class); + } + + /** + * Check if a middlewareGroup with the given name exists. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMiddlewareGroup($name) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->hasMiddlewareGroup($name); + } + + /** + * Get all of the defined middleware groups. + * + * @return array + * @static + */ + public static function getMiddlewareGroups() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getMiddlewareGroups(); + } + + /** + * Register a group of middleware. + * + * @param string $name + * @param array $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function middlewareGroup($name, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->middlewareGroup($name, $middleware); + } + + /** + * Add a middleware to the beginning of a middleware group. + * + * If the middleware is already in the group, it will not be added again. + * + * @param string $group + * @param string $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function prependMiddlewareToGroup($group, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->prependMiddlewareToGroup($group, $middleware); + } + + /** + * Add a middleware to the end of a middleware group. + * + * If the middleware is already in the group, it will not be added again. + * + * @param string $group + * @param string $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function pushMiddlewareToGroup($group, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->pushMiddlewareToGroup($group, $middleware); + } + + /** + * Remove the given middleware from the specified group. + * + * @param string $group + * @param string $middleware + * @return \Illuminate\Routing\Router + * @static + */ + public static function removeMiddlewareFromGroup($group, $middleware) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->removeMiddlewareFromGroup($group, $middleware); + } + + /** + * Flush the router's middleware groups. + * + * @return \Illuminate\Routing\Router + * @static + */ + public static function flushMiddlewareGroups() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->flushMiddlewareGroups(); + } + + /** + * Add a new route parameter binder. + * + * @param string $key + * @param string|callable $binder + * @return void + * @static + */ + public static function bind($key, $binder) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->bind($key, $binder); + } + + /** + * Register a model binder for a wildcard. + * + * @param string $key + * @param string $class + * @param \Closure|null $callback + * @return void + * @static + */ + public static function model($key, $class, $callback = null) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->model($key, $class, $callback); + } + + /** + * Get the binding callback for a given binding. + * + * @param string $key + * @return \Closure|null + * @static + */ + public static function getBindingCallback($key) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getBindingCallback($key); + } + + /** + * Get the global "where" patterns. + * + * @return array + * @static + */ + public static function getPatterns() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getPatterns(); + } + + /** + * Set a global where pattern on all routes. + * + * @param string $key + * @param string $pattern + * @return void + * @static + */ + public static function pattern($key, $pattern) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->pattern($key, $pattern); + } + + /** + * Set a group of global where patterns on all routes. + * + * @param array $patterns + * @return void + * @static + */ + public static function patterns($patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->patterns($patterns); + } + + /** + * Determine if the router currently has a group stack. + * + * @return bool + * @static + */ + public static function hasGroupStack() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->hasGroupStack(); + } + + /** + * Get the current group stack for the router. + * + * @return array + * @static + */ + public static function getGroupStack() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getGroupStack(); + } + + /** + * Get a route parameter for the current route. + * + * @param string $key + * @param string|null $default + * @return mixed + * @static + */ + public static function input($key, $default = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->input($key, $default); + } + + /** + * Get the request currently being dispatched. + * + * @return \Illuminate\Http\Request + * @static + */ + public static function getCurrentRequest() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getCurrentRequest(); + } + + /** + * Get the currently dispatched route instance. + * + * @return \Illuminate\Routing\Route|null + * @static + */ + public static function getCurrentRoute() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getCurrentRoute(); + } + + /** + * Get the currently dispatched route instance. + * + * @return \Illuminate\Routing\Route|null + * @static + */ + public static function current() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->current(); + } + + /** + * Check if a route with the given name exists. + * + * @param string|array $name + * @return bool + * @static + */ + public static function has($name) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->has($name); + } + + /** + * Get the current route name. + * + * @return string|null + * @static + */ + public static function currentRouteName() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteName(); + } + + /** + * Alias for the "currentRouteNamed" method. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function is(...$patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->is(...$patterns); + } + + /** + * Determine if the current route matches a pattern. + * + * @param mixed $patterns + * @return bool + * @static + */ + public static function currentRouteNamed(...$patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteNamed(...$patterns); + } + + /** + * Get the current route action. + * + * @return string|null + * @static + */ + public static function currentRouteAction() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteAction(); + } + + /** + * Alias for the "currentRouteUses" method. + * + * @param array|string $patterns + * @return bool + * @static + */ + public static function uses(...$patterns) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->uses(...$patterns); + } + + /** + * Determine if the current route action matches a given action. + * + * @param string $action + * @return bool + * @static + */ + public static function currentRouteUses($action) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->currentRouteUses($action); + } + + /** + * Set the unmapped global resource parameters to singular. + * + * @param bool $singular + * @return void + * @static + */ + public static function singularResourceParameters($singular = true) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->singularResourceParameters($singular); + } + + /** + * Set the global resource parameter mapping. + * + * @param array $parameters + * @return void + * @static + */ + public static function resourceParameters($parameters = []) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->resourceParameters($parameters); + } + + /** + * Get or set the verbs used in the resource URIs. + * + * @param array $verbs + * @return array|null + * @static + */ + public static function resourceVerbs($verbs = []) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->resourceVerbs($verbs); + } + + /** + * Get the underlying route collection. + * + * @return \Illuminate\Routing\RouteCollectionInterface + * @static + */ + public static function getRoutes() + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->getRoutes(); + } + + /** + * Set the route collection instance. + * + * @param \Illuminate\Routing\RouteCollection $routes + * @return void + * @static + */ + public static function setRoutes($routes) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->setRoutes($routes); + } + + /** + * Set the compiled route collection instance. + * + * @param array $routes + * @return void + * @static + */ + public static function setCompiledRoutes($routes) + { + /** @var \Illuminate\Routing\Router $instance */ + $instance->setCompiledRoutes($routes); + } + + /** + * Remove any duplicate middleware from the given array. + * + * @param array $middleware + * @return array + * @static + */ + public static function uniqueMiddleware($middleware) + { + return \Illuminate\Routing\Router::uniqueMiddleware($middleware); + } + + /** + * Set the container instance used by the router. + * + * @param \Illuminate\Container\Container $container + * @return \Illuminate\Routing\Router + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->setContainer($container); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\Router::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\Router::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\Router::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\Router::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->macroCall($method, $parameters); + } + + /** + * Call the given Closure with this instance then return the instance. + * + * @param (callable($this): mixed)|null $callback + * @return ($callback is null ? \Illuminate\Support\HigherOrderTapProxy : $this) + * @static + */ + public static function tap($callback = null) + { + /** @var \Illuminate\Routing\Router $instance */ + return $instance->tap($callback); + } + + } + /** + * + * + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes withoutOverlapping(int $expiresAt = 1440) + * @method static void mergeAttributes(\Illuminate\Console\Scheduling\Event $event) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes user(string $user) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes environments(array|mixed $environments) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes evenInMaintenanceMode() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes onOneServer() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes runInBackground() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes when(\Closure|bool $callback) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes skip(\Closure|bool $callback) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes name(string $description) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes description(string $description) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes cron(string $expression) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes between(string $startTime, string $endTime) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes unlessBetween(string $startTime, string $endTime) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everySecond() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwoSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFiveSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTenSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFifteenSeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwentySeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThirtySeconds() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyMinute() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwoMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThreeMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFourMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFiveMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTenMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFifteenMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThirtyMinutes() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes hourly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes hourlyAt(array|string|int|int[] $offset) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyOddHour(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyTwoHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyThreeHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everyFourHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes everySixHours(array|string|int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes daily() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes at(string $time) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes dailyAt(string $time) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes twiceDaily(int $first = 1, int $second = 13) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes twiceDailyAt(int $first = 1, int $second = 13, int $offset = 0) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weekdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weekends() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes mondays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes tuesdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes wednesdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes thursdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes fridays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes saturdays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes sundays() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weekly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes weeklyOn(array|mixed $dayOfWeek, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes monthly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes monthlyOn(int $dayOfMonth = 1, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes twiceMonthly(int $first = 1, int $second = 16, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes lastDayOfMonth(string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes quarterly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes quarterlyOn(int $dayOfQuarter = 1, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes yearly() + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes yearlyOn(int $month = 1, int|string $dayOfMonth = 1, string $time = '0:0') + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes days(array|mixed $days) + * @method static \Illuminate\Console\Scheduling\PendingEventAttributes timezone(\DateTimeZone|string $timezone) + * @see \Illuminate\Console\Scheduling\Schedule + */ + class Schedule { + /** + * Add a new callback event to the schedule. + * + * @param string|callable $callback + * @param array $parameters + * @return \Illuminate\Console\Scheduling\CallbackEvent + * @static + */ + public static function call($callback, $parameters = []) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->call($callback, $parameters); + } + + /** + * Add a new Artisan command event to the schedule. + * + * @param string $command + * @param array $parameters + * @return \Illuminate\Console\Scheduling\Event + * @static + */ + public static function command($command, $parameters = []) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->command($command, $parameters); + } + + /** + * Add a new job callback event to the schedule. + * + * @param object|string $job + * @param string|null $queue + * @param string|null $connection + * @return \Illuminate\Console\Scheduling\CallbackEvent + * @static + */ + public static function job($job, $queue = null, $connection = null) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->job($job, $queue, $connection); + } + + /** + * Add a new command event to the schedule. + * + * @param string $command + * @param array $parameters + * @return \Illuminate\Console\Scheduling\Event + * @static + */ + public static function exec($command, $parameters = []) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->exec($command, $parameters); + } + + /** + * Create new schedule group. + * + * @param \Illuminate\Console\Scheduling\Event $event + * @return void + * @throws \RuntimeException + * @static + */ + public static function group($events) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + $instance->group($events); + } + + /** + * Compile array input for a command. + * + * @param string|int $key + * @param array $value + * @return string + * @static + */ + public static function compileArrayInput($key, $value) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->compileArrayInput($key, $value); + } + + /** + * Determine if the server is allowed to run this event. + * + * @param \Illuminate\Console\Scheduling\Event $event + * @param \DateTimeInterface $time + * @return bool + * @static + */ + public static function serverShouldRun($event, $time) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->serverShouldRun($event, $time); + } + + /** + * Get all of the events on the schedule that are due. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Support\Collection + * @static + */ + public static function dueEvents($app) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->dueEvents($app); + } + + /** + * Get all of the events on the schedule. + * + * @return \Illuminate\Console\Scheduling\Event[] + * @static + */ + public static function events() + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->events(); + } + + /** + * Specify the cache store that should be used to store mutexes. + * + * @param string $store + * @return \Illuminate\Console\Scheduling\Schedule + * @static + */ + public static function useCache($store) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->useCache($store); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Console\Scheduling\Schedule::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Console\Scheduling\Schedule::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Console\Scheduling\Schedule::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Console\Scheduling\Schedule::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Console\Scheduling\Schedule $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Database\Schema\Builder + */ + class Schema { + /** + * Drop all tables from the database. + * + * @return void + * @static + */ + public static function dropAllTables() + { + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropAllTables(); + } + + /** + * Drop all views from the database. + * + * @return void + * @static + */ + public static function dropAllViews() + { + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropAllViews(); + } + + /** + * Get the names of current schemas for the connection. + * + * @return string[]|null + * @static + */ + public static function getCurrentSchemaListing() + { + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getCurrentSchemaListing(); + } + + /** + * Set the default string length for migrations. + * + * @param int $length + * @return void + * @static + */ + public static function defaultStringLength($length) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::defaultStringLength($length); + } + + /** + * Set the default time precision for migrations. + * + * @static + */ + public static function defaultTimePrecision($precision) + { + //Method inherited from \Illuminate\Database\Schema\Builder + return \Illuminate\Database\Schema\MySqlBuilder::defaultTimePrecision($precision); + } + + /** + * Set the default morph key type for migrations. + * + * @param string $type + * @return void + * @throws \InvalidArgumentException + * @static + */ + public static function defaultMorphKeyType($type) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::defaultMorphKeyType($type); + } + + /** + * Set the default morph key type for migrations to UUIDs. + * + * @return void + * @static + */ + public static function morphUsingUuids() + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::morphUsingUuids(); + } + + /** + * Set the default morph key type for migrations to ULIDs. + * + * @return void + * @static + */ + public static function morphUsingUlids() + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::morphUsingUlids(); + } + + /** + * Create a database in the schema. + * + * @param string $name + * @return bool + * @static + */ + public static function createDatabase($name) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->createDatabase($name); + } + + /** + * Drop a database from the schema if the database exists. + * + * @param string $name + * @return bool + * @static + */ + public static function dropDatabaseIfExists($name) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->dropDatabaseIfExists($name); + } + + /** + * Get the schemas that belong to the connection. + * + * @return array + * @static + */ + public static function getSchemas() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getSchemas(); + } + + /** + * Determine if the given table exists. + * + * @param string $table + * @return bool + * @static + */ + public static function hasTable($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasTable($table); + } + + /** + * Determine if the given view exists. + * + * @param string $view + * @return bool + * @static + */ + public static function hasView($view) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasView($view); + } + + /** + * Get the tables that belong to the connection. + * + * @param string|string[]|null $schema + * @return array + * @static + */ + public static function getTables($schema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getTables($schema); + } + + /** + * Get the names of the tables that belong to the connection. + * + * @param string|string[]|null $schema + * @param bool $schemaQualified + * @return array + * @static + */ + public static function getTableListing($schema = null, $schemaQualified = true) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getTableListing($schema, $schemaQualified); + } + + /** + * Get the views that belong to the connection. + * + * @param string|string[]|null $schema + * @return array + * @static + */ + public static function getViews($schema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getViews($schema); + } + + /** + * Get the user-defined types that belong to the connection. + * + * @param string|string[]|null $schema + * @return array + * @static + */ + public static function getTypes($schema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getTypes($schema); + } + + /** + * Determine if the given table has a given column. + * + * @param string $table + * @param string $column + * @return bool + * @static + */ + public static function hasColumn($table, $column) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasColumn($table, $column); + } + + /** + * Determine if the given table has given columns. + * + * @param string $table + * @param array $columns + * @return bool + * @static + */ + public static function hasColumns($table, $columns) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasColumns($table, $columns); + } + + /** + * Execute a table builder callback if the given table has a given column. + * + * @param string $table + * @param string $column + * @param \Closure $callback + * @return void + * @static + */ + public static function whenTableHasColumn($table, $column, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->whenTableHasColumn($table, $column, $callback); + } + + /** + * Execute a table builder callback if the given table doesn't have a given column. + * + * @param string $table + * @param string $column + * @param \Closure $callback + * @return void + * @static + */ + public static function whenTableDoesntHaveColumn($table, $column, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->whenTableDoesntHaveColumn($table, $column, $callback); + } + + /** + * Get the data type for the given column name. + * + * @param string $table + * @param string $column + * @param bool $fullDefinition + * @return string + * @static + */ + public static function getColumnType($table, $column, $fullDefinition = false) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getColumnType($table, $column, $fullDefinition); + } + + /** + * Get the column listing for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getColumnListing($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getColumnListing($table); + } + + /** + * Get the columns for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getColumns($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getColumns($table); + } + + /** + * Get the indexes for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getIndexes($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getIndexes($table); + } + + /** + * Get the names of the indexes for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getIndexListing($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getIndexListing($table); + } + + /** + * Determine if the given table has a given index. + * + * @param string $table + * @param string|array $index + * @param string|null $type + * @return bool + * @static + */ + public static function hasIndex($table, $index, $type = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->hasIndex($table, $index, $type); + } + + /** + * Get the foreign keys for a given table. + * + * @param string $table + * @return array + * @static + */ + public static function getForeignKeys($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getForeignKeys($table); + } + + /** + * Modify a table on the schema. + * + * @param string $table + * @param \Closure $callback + * @return void + * @static + */ + public static function table($table, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->table($table, $callback); + } + + /** + * Create a new table on the schema. + * + * @param string $table + * @param \Closure $callback + * @return void + * @static + */ + public static function create($table, $callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->create($table, $callback); + } + + /** + * Drop a table from the schema. + * + * @param string $table + * @return void + * @static + */ + public static function drop($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->drop($table); + } + + /** + * Drop a table from the schema if it exists. + * + * @param string $table + * @return void + * @static + */ + public static function dropIfExists($table) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropIfExists($table); + } + + /** + * Drop columns from a table schema. + * + * @param string $table + * @param string|array $columns + * @return void + * @static + */ + public static function dropColumns($table, $columns) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropColumns($table, $columns); + } + + /** + * Drop all types from the database. + * + * @return void + * @throws \LogicException + * @static + */ + public static function dropAllTypes() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->dropAllTypes(); + } + + /** + * Rename a table on the schema. + * + * @param string $from + * @param string $to + * @return void + * @static + */ + public static function rename($from, $to) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->rename($from, $to); + } + + /** + * Enable foreign key constraints. + * + * @return bool + * @static + */ + public static function enableForeignKeyConstraints() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->enableForeignKeyConstraints(); + } + + /** + * Disable foreign key constraints. + * + * @return bool + * @static + */ + public static function disableForeignKeyConstraints() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->disableForeignKeyConstraints(); + } + + /** + * Disable foreign key constraints during the execution of a callback. + * + * @param \Closure $callback + * @return mixed + * @static + */ + public static function withoutForeignKeyConstraints($callback) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->withoutForeignKeyConstraints($callback); + } + + /** + * Get the default schema name for the connection. + * + * @return string|null + * @static + */ + public static function getCurrentSchemaName() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getCurrentSchemaName(); + } + + /** + * Parse the given database object reference and extract the schema and table. + * + * @param string $reference + * @param string|bool|null $withDefaultSchema + * @return array + * @static + */ + public static function parseSchemaAndTable($reference, $withDefaultSchema = null) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->parseSchemaAndTable($reference, $withDefaultSchema); + } + + /** + * Get the database connection instance. + * + * @return \Illuminate\Database\Connection + * @static + */ + public static function getConnection() + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + return $instance->getConnection(); + } + + /** + * Set the Schema Blueprint resolver callback. + * + * @param \Closure $resolver + * @return void + * @static + */ + public static function blueprintResolver($resolver) + { + //Method inherited from \Illuminate\Database\Schema\Builder + /** @var \Illuminate\Database\Schema\MySqlBuilder $instance */ + $instance->blueprintResolver($resolver); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + //Method inherited from \Illuminate\Database\Schema\Builder + return \Illuminate\Database\Schema\MySqlBuilder::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + //Method inherited from \Illuminate\Database\Schema\Builder + \Illuminate\Database\Schema\MySqlBuilder::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Session\SessionManager + */ + class Session { + /** + * Determine if requests for the same session should wait for each to finish before executing. + * + * @return bool + * @static + */ + public static function shouldBlock() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->shouldBlock(); + } + + /** + * Get the name of the cache store / driver that should be used to acquire session locks. + * + * @return string|null + * @static + */ + public static function blockDriver() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->blockDriver(); + } + + /** + * Get the maximum number of seconds the session lock should be held for. + * + * @return int + * @static + */ + public static function defaultRouteBlockLockSeconds() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->defaultRouteBlockLockSeconds(); + } + + /** + * Get the maximum number of seconds to wait while attempting to acquire a route block session lock. + * + * @return int + * @static + */ + public static function defaultRouteBlockWaitSeconds() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->defaultRouteBlockWaitSeconds(); + } + + /** + * Get the session configuration. + * + * @return array + * @static + */ + public static function getSessionConfig() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getSessionConfig(); + } + + /** + * Get the default session driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Set the default session driver name. + * + * @param string $name + * @return void + * @static + */ + public static function setDefaultDriver($name) + { + /** @var \Illuminate\Session\SessionManager $instance */ + $instance->setDefaultDriver($name); + } + + /** + * Get a driver instance. + * + * @param string|null $driver + * @return mixed + * @throws \InvalidArgumentException + * @static + */ + public static function driver($driver = null) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->driver($driver); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Session\SessionManager + * @static + */ + public static function extend($driver, $callback) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Get all of the created "drivers". + * + * @return array + * @static + */ + public static function getDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getDrivers(); + } + + /** + * Get the container instance used by the manager. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the manager. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Session\SessionManager + * @static + */ + public static function setContainer($container) + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->setContainer($container); + } + + /** + * Forget all of the resolved driver instances. + * + * @return \Illuminate\Session\SessionManager + * @static + */ + public static function forgetDrivers() + { + //Method inherited from \Illuminate\Support\Manager + /** @var \Illuminate\Session\SessionManager $instance */ + return $instance->forgetDrivers(); + } + + /** + * Start the session, reading the data from a handler. + * + * @return bool + * @static + */ + public static function start() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->start(); + } + + /** + * Save the session data to storage. + * + * @return void + * @static + */ + public static function save() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->save(); + } + + /** + * Age the flash data for the session. + * + * @return void + * @static + */ + public static function ageFlashData() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->ageFlashData(); + } + + /** + * Get all of the session data. + * + * @return array + * @static + */ + public static function all() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->all(); + } + + /** + * Get a subset of the session data. + * + * @param array $keys + * @return array + * @static + */ + public static function only($keys) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->only($keys); + } + + /** + * Get all the session data except for a specified array of items. + * + * @param array $keys + * @return array + * @static + */ + public static function except($keys) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->except($keys); + } + + /** + * Checks if a key exists. + * + * @param string|array $key + * @return bool + * @static + */ + public static function exists($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->exists($key); + } + + /** + * Determine if the given key is missing from the session data. + * + * @param string|array $key + * @return bool + * @static + */ + public static function missing($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->missing($key); + } + + /** + * Determine if a key is present and not null. + * + * @param string|array $key + * @return bool + * @static + */ + public static function has($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->has($key); + } + + /** + * Determine if any of the given keys are present and not null. + * + * @param string|array $key + * @return bool + * @static + */ + public static function hasAny($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->hasAny($key); + } + + /** + * Get an item from the session. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function get($key, $default = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->get($key, $default); + } + + /** + * Get the value of a given key and then forget it. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function pull($key, $default = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->pull($key, $default); + } + + /** + * Determine if the session contains old input. + * + * @param string|null $key + * @return bool + * @static + */ + public static function hasOldInput($key = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->hasOldInput($key); + } + + /** + * Get the requested item from the flashed input array. + * + * @param string|null $key + * @param mixed $default + * @return mixed + * @static + */ + public static function getOldInput($key = null, $default = null) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getOldInput($key, $default); + } + + /** + * Replace the given session attributes entirely. + * + * @param array $attributes + * @return void + * @static + */ + public static function replace($attributes) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->replace($attributes); + } + + /** + * Put a key / value pair or array of key / value pairs in the session. + * + * @param string|array $key + * @param mixed $value + * @return void + * @static + */ + public static function put($key, $value = null) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->put($key, $value); + } + + /** + * Get an item from the session, or store the default value. + * + * @param string $key + * @param \Closure $callback + * @return mixed + * @static + */ + public static function remember($key, $callback) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->remember($key, $callback); + } + + /** + * Push a value onto a session array. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function push($key, $value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->push($key, $value); + } + + /** + * Increment the value of an item in the session. + * + * @param string $key + * @param int $amount + * @return mixed + * @static + */ + public static function increment($key, $amount = 1) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->increment($key, $amount); + } + + /** + * Decrement the value of an item in the session. + * + * @param string $key + * @param int $amount + * @return int + * @static + */ + public static function decrement($key, $amount = 1) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->decrement($key, $amount); + } + + /** + * Flash a key / value pair to the session. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function flash($key, $value = true) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->flash($key, $value); + } + + /** + * Flash a key / value pair to the session for immediate use. + * + * @param string $key + * @param mixed $value + * @return void + * @static + */ + public static function now($key, $value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->now($key, $value); + } + + /** + * Reflash all of the session flash data. + * + * @return void + * @static + */ + public static function reflash() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->reflash(); + } + + /** + * Reflash a subset of the current flash data. + * + * @param array|mixed $keys + * @return void + * @static + */ + public static function keep($keys = null) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->keep($keys); + } + + /** + * Flash an input array to the session. + * + * @param array $value + * @return void + * @static + */ + public static function flashInput($value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->flashInput($value); + } + + /** + * Remove an item from the session, returning its value. + * + * @param string $key + * @return mixed + * @static + */ + public static function remove($key) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->remove($key); + } + + /** + * Remove one or many items from the session. + * + * @param string|array $keys + * @return void + * @static + */ + public static function forget($keys) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->forget($keys); + } + + /** + * Remove all of the items from the session. + * + * @return void + * @static + */ + public static function flush() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->flush(); + } + + /** + * Flush the session data and regenerate the ID. + * + * @return bool + * @static + */ + public static function invalidate() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->invalidate(); + } + + /** + * Generate a new session identifier. + * + * @param bool $destroy + * @return bool + * @static + */ + public static function regenerate($destroy = false) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->regenerate($destroy); + } + + /** + * Generate a new session ID for the session. + * + * @param bool $destroy + * @return bool + * @static + */ + public static function migrate($destroy = false) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->migrate($destroy); + } + + /** + * Determine if the session has been started. + * + * @return bool + * @static + */ + public static function isStarted() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->isStarted(); + } + + /** + * Get the name of the session. + * + * @return string + * @static + */ + public static function getName() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getName(); + } + + /** + * Set the name of the session. + * + * @param string $name + * @return void + * @static + */ + public static function setName($name) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setName($name); + } + + /** + * Get the current session ID. + * + * @return string + * @static + */ + public static function id() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->id(); + } + + /** + * Get the current session ID. + * + * @return string + * @static + */ + public static function getId() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getId(); + } + + /** + * Set the session ID. + * + * @param string|null $id + * @return void + * @static + */ + public static function setId($id) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setId($id); + } + + /** + * Determine if this is a valid session ID. + * + * @param string|null $id + * @return bool + * @static + */ + public static function isValidId($id) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->isValidId($id); + } + + /** + * Set the existence of the session on the handler if applicable. + * + * @param bool $value + * @return void + * @static + */ + public static function setExists($value) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setExists($value); + } + + /** + * Get the CSRF token value. + * + * @return string + * @static + */ + public static function token() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->token(); + } + + /** + * Regenerate the CSRF token value. + * + * @return void + * @static + */ + public static function regenerateToken() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->regenerateToken(); + } + + /** + * Determine if the previous URI is available. + * + * @return bool + * @static + */ + public static function hasPreviousUri() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->hasPreviousUri(); + } + + /** + * Get the previous URL from the session as a URI instance. + * + * @return \Illuminate\Support\Uri + * @throws \RuntimeException + * @static + */ + public static function previousUri() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->previousUri(); + } + + /** + * Get the previous URL from the session. + * + * @return string|null + * @static + */ + public static function previousUrl() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->previousUrl(); + } + + /** + * Set the "previous" URL in the session. + * + * @param string $url + * @return void + * @static + */ + public static function setPreviousUrl($url) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setPreviousUrl($url); + } + + /** + * Specify that the user has confirmed their password. + * + * @return void + * @static + */ + public static function passwordConfirmed() + { + /** @var \Illuminate\Session\Store $instance */ + $instance->passwordConfirmed(); + } + + /** + * Get the underlying session handler implementation. + * + * @return \SessionHandlerInterface + * @static + */ + public static function getHandler() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->getHandler(); + } + + /** + * Set the underlying session handler implementation. + * + * @param \SessionHandlerInterface $handler + * @return \SessionHandlerInterface + * @static + */ + public static function setHandler($handler) + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->setHandler($handler); + } + + /** + * Determine if the session handler needs a request. + * + * @return bool + * @static + */ + public static function handlerNeedsRequest() + { + /** @var \Illuminate\Session\Store $instance */ + return $instance->handlerNeedsRequest(); + } + + /** + * Set the request on the handler instance. + * + * @param \Illuminate\Http\Request $request + * @return void + * @static + */ + public static function setRequestOnHandler($request) + { + /** @var \Illuminate\Session\Store $instance */ + $instance->setRequestOnHandler($request); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Session\Store::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Session\Store::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Session\Store::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Session\Store::flushMacros(); + } + + } + /** + * + * + * @method static bool has(string $location) + * @method static string read(string $location) + * @method static \League\Flysystem\DirectoryListing listContents(string $location, bool $deep = false) + * @method static int fileSize(string $path) + * @method static string visibility(string $path) + * @method static void write(string $location, string $contents, array $config = []) + * @method static void createDirectory(string $location, array $config = []) + * @see \Illuminate\Filesystem\FilesystemManager + */ + class Storage { + /** + * Get a filesystem instance. + * + * @param string|null $name + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function drive($name = null) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->drive($name); + } + + /** + * Get a filesystem instance. + * + * @param string|null $name + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function disk($name = null) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->disk($name); + } + + /** + * Get a default cloud filesystem instance. + * + * @return \Illuminate\Contracts\Filesystem\Cloud + * @static + */ + public static function cloud() + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->cloud(); + } + + /** + * Build an on-demand disk. + * + * @param string|array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function build($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->build($config); + } + + /** + * Create an instance of the local driver. + * + * @param array $config + * @param string $name + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createLocalDriver($config, $name = 'local') + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createLocalDriver($config, $name); + } + + /** + * Create an instance of the ftp driver. + * + * @param array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createFtpDriver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createFtpDriver($config); + } + + /** + * Create an instance of the sftp driver. + * + * @param array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createSftpDriver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createSftpDriver($config); + } + + /** + * Create an instance of the Amazon S3 driver. + * + * @param array $config + * @return \Illuminate\Contracts\Filesystem\Cloud + * @static + */ + public static function createS3Driver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createS3Driver($config); + } + + /** + * Create a scoped driver. + * + * @param array $config + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function createScopedDriver($config) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->createScopedDriver($config); + } + + /** + * Set the given disk instance. + * + * @param string $name + * @param mixed $disk + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function set($name, $disk) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->set($name, $disk); + } + + /** + * Get the default driver name. + * + * @return string + * @static + */ + public static function getDefaultDriver() + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->getDefaultDriver(); + } + + /** + * Get the default cloud driver name. + * + * @return string + * @static + */ + public static function getDefaultCloudDriver() + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->getDefaultCloudDriver(); + } + + /** + * Unset the given disk instances. + * + * @param array|string $disk + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function forgetDisk($disk) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->forgetDisk($disk); + } + + /** + * Disconnect the given disk and remove from local cache. + * + * @param string|null $name + * @return void + * @static + */ + public static function purge($name = null) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + $instance->purge($name); + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function extend($driver, $callback) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->extend($driver, $callback); + } + + /** + * Set the application instance used by the manager. + * + * @param \Illuminate\Contracts\Foundation\Application $app + * @return \Illuminate\Filesystem\FilesystemManager + * @static + */ + public static function setApplication($app) + { + /** @var \Illuminate\Filesystem\FilesystemManager $instance */ + return $instance->setApplication($app); + } + + /** + * Determine if temporary URLs can be generated. + * + * @return bool + * @static + */ + public static function providesTemporaryUrls() + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->providesTemporaryUrls(); + } + + /** + * Get a temporary URL for the file at the given path. + * + * @param string $path + * @param \DateTimeInterface $expiration + * @param array $options + * @return string + * @static + */ + public static function temporaryUrl($path, $expiration, $options = []) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->temporaryUrl($path, $expiration, $options); + } + + /** + * Specify the name of the disk the adapter is managing. + * + * @param string $disk + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function diskName($disk) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->diskName($disk); + } + + /** + * Indicate that signed URLs should serve the corresponding files. + * + * @param bool $serve + * @param \Closure|null $urlGeneratorResolver + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function shouldServeSignedUrls($serve = true, $urlGeneratorResolver = null) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->shouldServeSignedUrls($serve, $urlGeneratorResolver); + } + + /** + * Assert that the given file or directory exists. + * + * @param string|array $path + * @param string|null $content + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertExists($path, $content = null) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertExists($path, $content); + } + + /** + * Assert that the number of files in path equals the expected count. + * + * @param string $path + * @param int $count + * @param bool $recursive + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertCount($path, $count, $recursive = false) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertCount($path, $count, $recursive); + } + + /** + * Assert that the given file or directory does not exist. + * + * @param string|array $path + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertMissing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertMissing($path); + } + + /** + * Assert that the given directory is empty. + * + * @param string $path + * @return \Illuminate\Filesystem\LocalFilesystemAdapter + * @static + */ + public static function assertDirectoryEmpty($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->assertDirectoryEmpty($path); + } + + /** + * Determine if a file or directory exists. + * + * @param string $path + * @return bool + * @static + */ + public static function exists($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->exists($path); + } + + /** + * Determine if a file or directory is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function missing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->missing($path); + } + + /** + * Determine if a file exists. + * + * @param string $path + * @return bool + * @static + */ + public static function fileExists($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->fileExists($path); + } + + /** + * Determine if a file is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function fileMissing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->fileMissing($path); + } + + /** + * Determine if a directory exists. + * + * @param string $path + * @return bool + * @static + */ + public static function directoryExists($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->directoryExists($path); + } + + /** + * Determine if a directory is missing. + * + * @param string $path + * @return bool + * @static + */ + public static function directoryMissing($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->directoryMissing($path); + } + + /** + * Get the full path to the file that exists at the given relative path. + * + * @param string $path + * @return string + * @static + */ + public static function path($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->path($path); + } + + /** + * Get the contents of a file. + * + * @param string $path + * @return string|null + * @static + */ + public static function get($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->get($path); + } + + /** + * Get the contents of a file as decoded JSON. + * + * @param string $path + * @param int $flags + * @return array|null + * @static + */ + public static function json($path, $flags = 0) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->json($path, $flags); + } + + /** + * Create a streamed response for a given file. + * + * @param string $path + * @param string|null $name + * @param array $headers + * @param string|null $disposition + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function response($path, $name = null, $headers = [], $disposition = 'inline') + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->response($path, $name, $headers, $disposition); + } + + /** + * Create a streamed download response for a given file. + * + * @param \Illuminate\Http\Request $request + * @param string $path + * @param string|null $name + * @param array $headers + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function serve($request, $path, $name = null, $headers = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->serve($request, $path, $name, $headers); + } + + /** + * Create a streamed download response for a given file. + * + * @param string $path + * @param string|null $name + * @param array $headers + * @return \Symfony\Component\HttpFoundation\StreamedResponse + * @static + */ + public static function download($path, $name = null, $headers = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->download($path, $name, $headers); + } + + /** + * Write the contents of a file. + * + * @param string $path + * @param \Psr\Http\Message\StreamInterface|\Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|resource $contents + * @param mixed $options + * @return string|bool + * @static + */ + public static function put($path, $contents, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->put($path, $contents, $options); + } + + /** + * Store the uploaded file on the disk. + * + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $path + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|array|null $file + * @param mixed $options + * @return string|false + * @static + */ + public static function putFile($path, $file = null, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->putFile($path, $file, $options); + } + + /** + * Store the uploaded file on the disk with a given name. + * + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string $path + * @param \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|array|null $file + * @param string|array|null $name + * @param mixed $options + * @return string|false + * @static + */ + public static function putFileAs($path, $file, $name = null, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->putFileAs($path, $file, $name, $options); + } + + /** + * Get the visibility for the given path. + * + * @param string $path + * @return string + * @static + */ + public static function getVisibility($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getVisibility($path); + } + + /** + * Set the visibility for the given path. + * + * @param string $path + * @param string $visibility + * @return bool + * @static + */ + public static function setVisibility($path, $visibility) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->setVisibility($path, $visibility); + } + + /** + * Prepend to a file. + * + * @param string $path + * @param string $data + * @param string $separator + * @return bool + * @static + */ + public static function prepend($path, $data, $separator = ' +') + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->prepend($path, $data, $separator); + } + + /** + * Append to a file. + * + * @param string $path + * @param string $data + * @param string $separator + * @return bool + * @static + */ + public static function append($path, $data, $separator = ' +') + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->append($path, $data, $separator); + } + + /** + * Delete the file at a given path. + * + * @param string|array $paths + * @return bool + * @static + */ + public static function delete($paths) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->delete($paths); + } + + /** + * Copy a file to a new location. + * + * @param string $from + * @param string $to + * @return bool + * @static + */ + public static function copy($from, $to) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->copy($from, $to); + } + + /** + * Move a file to a new location. + * + * @param string $from + * @param string $to + * @return bool + * @static + */ + public static function move($from, $to) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->move($from, $to); + } + + /** + * Get the file size of a given file. + * + * @param string $path + * @return int + * @static + */ + public static function size($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->size($path); + } + + /** + * Get the checksum for a file. + * + * @return string|false + * @throws UnableToProvideChecksum + * @static + */ + public static function checksum($path, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->checksum($path, $options); + } + + /** + * Get the mime-type of a given file. + * + * @param string $path + * @return string|false + * @static + */ + public static function mimeType($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->mimeType($path); + } + + /** + * Get the file's last modification time. + * + * @param string $path + * @return int + * @static + */ + public static function lastModified($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->lastModified($path); + } + + /** + * Get a resource to read the file. + * + * @param string $path + * @return resource|null The path resource or null on failure. + * @static + */ + public static function readStream($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->readStream($path); + } + + /** + * Write a new file using a stream. + * + * @param string $path + * @param resource $resource + * @param array $options + * @return bool + * @static + */ + public static function writeStream($path, $resource, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->writeStream($path, $resource, $options); + } + + /** + * Get the URL for the file at the given path. + * + * @param string $path + * @return string + * @throws \RuntimeException + * @static + */ + public static function url($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->url($path); + } + + /** + * Get a temporary upload URL for the file at the given path. + * + * @param string $path + * @param \DateTimeInterface $expiration + * @param array $options + * @return array + * @throws \RuntimeException + * @static + */ + public static function temporaryUploadUrl($path, $expiration, $options = []) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->temporaryUploadUrl($path, $expiration, $options); + } + + /** + * Get an array of all files in a directory. + * + * @param string|null $directory + * @param bool $recursive + * @return array + * @static + */ + public static function files($directory = null, $recursive = false) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->files($directory, $recursive); + } + + /** + * Get all of the files from the given directory (recursive). + * + * @param string|null $directory + * @return array + * @static + */ + public static function allFiles($directory = null) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->allFiles($directory); + } + + /** + * Get all of the directories within a given directory. + * + * @param string|null $directory + * @param bool $recursive + * @return array + * @static + */ + public static function directories($directory = null, $recursive = false) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->directories($directory, $recursive); + } + + /** + * Get all the directories within a given directory (recursive). + * + * @param string|null $directory + * @return array + * @static + */ + public static function allDirectories($directory = null) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->allDirectories($directory); + } + + /** + * Create a directory. + * + * @param string $path + * @return bool + * @static + */ + public static function makeDirectory($path) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->makeDirectory($path); + } + + /** + * Recursively delete a directory. + * + * @param string $directory + * @return bool + * @static + */ + public static function deleteDirectory($directory) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->deleteDirectory($directory); + } + + /** + * Get the Flysystem driver. + * + * @return \League\Flysystem\FilesystemOperator + * @static + */ + public static function getDriver() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getDriver(); + } + + /** + * Get the Flysystem adapter. + * + * @return \League\Flysystem\FilesystemAdapter + * @static + */ + public static function getAdapter() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getAdapter(); + } + + /** + * Get the configuration values. + * + * @return array + * @static + */ + public static function getConfig() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->getConfig(); + } + + /** + * Define a custom callback that generates file download responses. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function serveUsing($callback) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + $instance->serveUsing($callback); + } + + /** + * Define a custom temporary URL builder callback. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function buildTemporaryUrlsUsing($callback) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + $instance->buildTemporaryUrlsUsing($callback); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + \Illuminate\Filesystem\LocalFilesystemAdapter::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + \Illuminate\Filesystem\LocalFilesystemAdapter::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + return \Illuminate\Filesystem\LocalFilesystemAdapter::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + \Illuminate\Filesystem\LocalFilesystemAdapter::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + //Method inherited from \Illuminate\Filesystem\FilesystemAdapter + /** @var \Illuminate\Filesystem\LocalFilesystemAdapter $instance */ + return $instance->macroCall($method, $parameters); + } + + } + /** + * + * + * @see \Illuminate\Routing\UrlGenerator + */ + class URL { + /** + * Get the full URL for the current request. + * + * @return string + * @static + */ + public static function full() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->full(); + } + + /** + * Get the current URL for the request. + * + * @return string + * @static + */ + public static function current() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->current(); + } + + /** + * Get the URL for the previous request. + * + * @param mixed $fallback + * @return string + * @static + */ + public static function previous($fallback = false) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->previous($fallback); + } + + /** + * Get the previous path info for the request. + * + * @param mixed $fallback + * @return string + * @static + */ + public static function previousPath($fallback = false) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->previousPath($fallback); + } + + /** + * Generate an absolute URL to the given path. + * + * @param string $path + * @param mixed $extra + * @param bool|null $secure + * @return string + * @static + */ + public static function to($path, $extra = [], $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->to($path, $extra, $secure); + } + + /** + * Generate an absolute URL with the given query parameters. + * + * @param string $path + * @param array $query + * @param mixed $extra + * @param bool|null $secure + * @return string + * @static + */ + public static function query($path, $query = [], $extra = [], $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->query($path, $query, $extra, $secure); + } + + /** + * Generate a secure, absolute URL to the given path. + * + * @param string $path + * @param array $parameters + * @return string + * @static + */ + public static function secure($path, $parameters = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->secure($path, $parameters); + } + + /** + * Generate the URL to an application asset. + * + * @param string $path + * @param bool|null $secure + * @return string + * @static + */ + public static function asset($path, $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->asset($path, $secure); + } + + /** + * Generate the URL to a secure asset. + * + * @param string $path + * @return string + * @static + */ + public static function secureAsset($path) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->secureAsset($path); + } + + /** + * Generate the URL to an asset from a custom root domain such as CDN, etc. + * + * @param string $root + * @param string $path + * @param bool|null $secure + * @return string + * @static + */ + public static function assetFrom($root, $path, $secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->assetFrom($root, $path, $secure); + } + + /** + * Get the default scheme for a raw URL. + * + * @param bool|null $secure + * @return string + * @static + */ + public static function formatScheme($secure = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatScheme($secure); + } + + /** + * Create a signed route URL for a named route. + * + * @param \BackedEnum|string $name + * @param mixed $parameters + * @param \DateTimeInterface|\DateInterval|int|null $expiration + * @param bool $absolute + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function signedRoute($name, $parameters = [], $expiration = null, $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->signedRoute($name, $parameters, $expiration, $absolute); + } + + /** + * Create a temporary signed route URL for a named route. + * + * @param \BackedEnum|string $name + * @param \DateTimeInterface|\DateInterval|int $expiration + * @param array $parameters + * @param bool $absolute + * @return string + * @static + */ + public static function temporarySignedRoute($name, $expiration, $parameters = [], $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->temporarySignedRoute($name, $expiration, $parameters, $absolute); + } + + /** + * Determine if the given request has a valid signature. + * + * @param \Illuminate\Http\Request $request + * @param bool $absolute + * @param \Closure|array $ignoreQuery + * @return bool + * @static + */ + public static function hasValidSignature($request, $absolute = true, $ignoreQuery = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->hasValidSignature($request, $absolute, $ignoreQuery); + } + + /** + * Determine if the given request has a valid signature for a relative URL. + * + * @param \Illuminate\Http\Request $request + * @param \Closure|array $ignoreQuery + * @return bool + * @static + */ + public static function hasValidRelativeSignature($request, $ignoreQuery = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->hasValidRelativeSignature($request, $ignoreQuery); + } + + /** + * Determine if the signature from the given request matches the URL. + * + * @param \Illuminate\Http\Request $request + * @param bool $absolute + * @param \Closure|array $ignoreQuery + * @return bool + * @static + */ + public static function hasCorrectSignature($request, $absolute = true, $ignoreQuery = []) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->hasCorrectSignature($request, $absolute, $ignoreQuery); + } + + /** + * Determine if the expires timestamp from the given request is not from the past. + * + * @param \Illuminate\Http\Request $request + * @return bool + * @static + */ + public static function signatureHasNotExpired($request) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->signatureHasNotExpired($request); + } + + /** + * Get the URL to a named route. + * + * @param \BackedEnum|string $name + * @param mixed $parameters + * @param bool $absolute + * @return string + * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException|\InvalidArgumentException + * @static + */ + public static function route($name, $parameters = [], $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->route($name, $parameters, $absolute); + } + + /** + * Get the URL for a given route instance. + * + * @param \Illuminate\Routing\Route $route + * @param mixed $parameters + * @param bool $absolute + * @return string + * @throws \Illuminate\Routing\Exceptions\UrlGenerationException + * @static + */ + public static function toRoute($route, $parameters, $absolute) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->toRoute($route, $parameters, $absolute); + } + + /** + * Get the URL to a controller action. + * + * @param string|array $action + * @param mixed $parameters + * @param bool $absolute + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function action($action, $parameters = [], $absolute = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->action($action, $parameters, $absolute); + } + + /** + * Format the array of URL parameters. + * + * @param mixed $parameters + * @return array + * @static + */ + public static function formatParameters($parameters) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatParameters($parameters); + } + + /** + * Get the base URL for the request. + * + * @param string $scheme + * @param string|null $root + * @return string + * @static + */ + public static function formatRoot($scheme, $root = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatRoot($scheme, $root); + } + + /** + * Format the given URL segments into a single URL. + * + * @param string $root + * @param string $path + * @param \Illuminate\Routing\Route|null $route + * @return string + * @static + */ + public static function format($root, $path, $route = null) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->format($root, $path, $route); + } + + /** + * Determine if the given path is a valid URL. + * + * @param string $path + * @return bool + * @static + */ + public static function isValidUrl($path) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->isValidUrl($path); + } + + /** + * Set the default named parameters used by the URL generator. + * + * @param array $defaults + * @return void + * @static + */ + public static function defaults($defaults) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->defaults($defaults); + } + + /** + * Get the default named parameters used by the URL generator. + * + * @return array + * @static + */ + public static function getDefaultParameters() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->getDefaultParameters(); + } + + /** + * Force the scheme for URLs. + * + * @param string|null $scheme + * @return void + * @static + */ + public static function forceScheme($scheme) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->forceScheme($scheme); + } + + /** + * Force the use of the HTTPS scheme for all generated URLs. + * + * @param bool $force + * @return void + * @static + */ + public static function forceHttps($force = true) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->forceHttps($force); + } + + /** + * Set the URL origin for all generated URLs. + * + * @param string|null $root + * @return void + * @static + */ + public static function useOrigin($root) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->useOrigin($root); + } + + /** + * Set the forced root URL. + * + * @param string|null $root + * @return void + * @deprecated Use useOrigin + * @static + */ + public static function forceRootUrl($root) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->forceRootUrl($root); + } + + /** + * Set the URL origin for all generated asset URLs. + * + * @param string|null $root + * @return void + * @static + */ + public static function useAssetOrigin($root) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->useAssetOrigin($root); + } + + /** + * Set a callback to be used to format the host of generated URLs. + * + * @param \Closure $callback + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function formatHostUsing($callback) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatHostUsing($callback); + } + + /** + * Set a callback to be used to format the path of generated URLs. + * + * @param \Closure $callback + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function formatPathUsing($callback) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->formatPathUsing($callback); + } + + /** + * Get the path formatter being used by the URL generator. + * + * @return \Closure + * @static + */ + public static function pathFormatter() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->pathFormatter(); + } + + /** + * Get the request instance. + * + * @return \Illuminate\Http\Request + * @static + */ + public static function getRequest() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->getRequest(); + } + + /** + * Set the current request instance. + * + * @param \Illuminate\Http\Request $request + * @return void + * @static + */ + public static function setRequest($request) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + $instance->setRequest($request); + } + + /** + * Set the route collection. + * + * @param \Illuminate\Routing\RouteCollectionInterface $routes + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setRoutes($routes) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setRoutes($routes); + } + + /** + * Set the session resolver for the generator. + * + * @param callable $sessionResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setSessionResolver($sessionResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setSessionResolver($sessionResolver); + } + + /** + * Set the encryption key resolver. + * + * @param callable $keyResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setKeyResolver($keyResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setKeyResolver($keyResolver); + } + + /** + * Clone a new instance of the URL generator with a different encryption key resolver. + * + * @param callable $keyResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function withKeyResolver($keyResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->withKeyResolver($keyResolver); + } + + /** + * Set the callback that should be used to attempt to resolve missing named routes. + * + * @param callable $missingNamedRouteResolver + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function resolveMissingNamedRoutesUsing($missingNamedRouteResolver) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->resolveMissingNamedRoutesUsing($missingNamedRouteResolver); + } + + /** + * Get the root controller namespace. + * + * @return string + * @static + */ + public static function getRootControllerNamespace() + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->getRootControllerNamespace(); + } + + /** + * Set the root controller namespace. + * + * @param string $rootNamespace + * @return \Illuminate\Routing\UrlGenerator + * @static + */ + public static function setRootControllerNamespace($rootNamespace) + { + /** @var \Illuminate\Routing\UrlGenerator $instance */ + return $instance->setRootControllerNamespace($rootNamespace); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Routing\UrlGenerator::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Routing\UrlGenerator::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Routing\UrlGenerator::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Routing\UrlGenerator::flushMacros(); + } + + } + /** + * + * + * @see \Illuminate\Validation\Factory + */ + class Validator { + /** + * Create a new Validator instance. + * + * @param array $data + * @param array $rules + * @param array $messages + * @param array $attributes + * @return \Illuminate\Validation\Validator + * @static + */ + public static function make($data, $rules, $messages = [], $attributes = []) + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->make($data, $rules, $messages, $attributes); + } + + /** + * Validate the given data against the provided rules. + * + * @param array $data + * @param array $rules + * @param array $messages + * @param array $attributes + * @return array + * @throws \Illuminate\Validation\ValidationException + * @static + */ + public static function validate($data, $rules, $messages = [], $attributes = []) + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->validate($data, $rules, $messages, $attributes); + } + + /** + * Register a custom validator extension. + * + * @param string $rule + * @param \Closure|string $extension + * @param string|null $message + * @return void + * @static + */ + public static function extend($rule, $extension, $message = null) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->extend($rule, $extension, $message); + } + + /** + * Register a custom implicit validator extension. + * + * @param string $rule + * @param \Closure|string $extension + * @param string|null $message + * @return void + * @static + */ + public static function extendImplicit($rule, $extension, $message = null) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->extendImplicit($rule, $extension, $message); + } + + /** + * Register a custom dependent validator extension. + * + * @param string $rule + * @param \Closure|string $extension + * @param string|null $message + * @return void + * @static + */ + public static function extendDependent($rule, $extension, $message = null) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->extendDependent($rule, $extension, $message); + } + + /** + * Register a custom validator message replacer. + * + * @param string $rule + * @param \Closure|string $replacer + * @return void + * @static + */ + public static function replacer($rule, $replacer) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->replacer($rule, $replacer); + } + + /** + * Indicate that unvalidated array keys should be included in validated data when the parent array is validated. + * + * @return void + * @static + */ + public static function includeUnvalidatedArrayKeys() + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->includeUnvalidatedArrayKeys(); + } + + /** + * Indicate that unvalidated array keys should be excluded from the validated data, even if the parent array was validated. + * + * @return void + * @static + */ + public static function excludeUnvalidatedArrayKeys() + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->excludeUnvalidatedArrayKeys(); + } + + /** + * Set the Validator instance resolver. + * + * @param \Closure $resolver + * @return void + * @static + */ + public static function resolver($resolver) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->resolver($resolver); + } + + /** + * Get the Translator implementation. + * + * @return \Illuminate\Contracts\Translation\Translator + * @static + */ + public static function getTranslator() + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->getTranslator(); + } + + /** + * Get the Presence Verifier implementation. + * + * @return \Illuminate\Validation\PresenceVerifierInterface + * @static + */ + public static function getPresenceVerifier() + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->getPresenceVerifier(); + } + + /** + * Set the Presence Verifier implementation. + * + * @param \Illuminate\Validation\PresenceVerifierInterface $presenceVerifier + * @return void + * @static + */ + public static function setPresenceVerifier($presenceVerifier) + { + /** @var \Illuminate\Validation\Factory $instance */ + $instance->setPresenceVerifier($presenceVerifier); + } + + /** + * Get the container instance used by the validation factory. + * + * @return \Illuminate\Contracts\Container\Container|null + * @static + */ + public static function getContainer() + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->getContainer(); + } + + /** + * Set the container instance used by the validation factory. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return \Illuminate\Validation\Factory + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\Validation\Factory $instance */ + return $instance->setContainer($container); + } + + } + /** + * + * + * @see \Illuminate\View\Factory + */ + class View { + /** + * Get the evaluated view contents for the given view. + * + * @param string $path + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return \Illuminate\Contracts\View\View + * @static + */ + public static function file($path, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->file($path, $data, $mergeData); + } + + /** + * Get the evaluated view contents for the given view. + * + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return \Illuminate\Contracts\View\View + * @static + */ + public static function make($view, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->make($view, $data, $mergeData); + } + + /** + * Get the first view that actually exists from the given list. + * + * @param array $views + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return \Illuminate\Contracts\View\View + * @throws \InvalidArgumentException + * @static + */ + public static function first($views, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->first($views, $data, $mergeData); + } + + /** + * Get the rendered content of the view based on a given condition. + * + * @param bool $condition + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return string + * @static + */ + public static function renderWhen($condition, $view, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderWhen($condition, $view, $data, $mergeData); + } + + /** + * Get the rendered content of the view based on the negation of a given condition. + * + * @param bool $condition + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData + * @return string + * @static + */ + public static function renderUnless($condition, $view, $data = [], $mergeData = []) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderUnless($condition, $view, $data, $mergeData); + } + + /** + * Get the rendered contents of a partial from a loop. + * + * @param string $view + * @param array $data + * @param string $iterator + * @param string $empty + * @return string + * @static + */ + public static function renderEach($view, $data, $iterator, $empty = 'raw|') + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderEach($view, $data, $iterator, $empty); + } + + /** + * Determine if a given view exists. + * + * @param string $view + * @return bool + * @static + */ + public static function exists($view) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->exists($view); + } + + /** + * Get the appropriate view engine for the given path. + * + * @param string $path + * @return \Illuminate\Contracts\View\Engine + * @throws \InvalidArgumentException + * @static + */ + public static function getEngineFromPath($path) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getEngineFromPath($path); + } + + /** + * Add a piece of shared data to the environment. + * + * @param array|string $key + * @param mixed|null $value + * @return mixed + * @static + */ + public static function share($key, $value = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->share($key, $value); + } + + /** + * Increment the rendering counter. + * + * @return void + * @static + */ + public static function incrementRender() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->incrementRender(); + } + + /** + * Decrement the rendering counter. + * + * @return void + * @static + */ + public static function decrementRender() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->decrementRender(); + } + + /** + * Check if there are no active render operations. + * + * @return bool + * @static + */ + public static function doneRendering() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->doneRendering(); + } + + /** + * Determine if the given once token has been rendered. + * + * @param string $id + * @return bool + * @static + */ + public static function hasRenderedOnce($id) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->hasRenderedOnce($id); + } + + /** + * Mark the given once token as having been rendered. + * + * @param string $id + * @return void + * @static + */ + public static function markAsRenderedOnce($id) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->markAsRenderedOnce($id); + } + + /** + * Add a location to the array of view locations. + * + * @param string $location + * @return void + * @static + */ + public static function addLocation($location) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->addLocation($location); + } + + /** + * Prepend a location to the array of view locations. + * + * @param string $location + * @return void + * @static + */ + public static function prependLocation($location) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->prependLocation($location); + } + + /** + * Add a new namespace to the loader. + * + * @param string $namespace + * @param string|array $hints + * @return \Illuminate\View\Factory + * @static + */ + public static function addNamespace($namespace, $hints) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->addNamespace($namespace, $hints); + } + + /** + * Prepend a new namespace to the loader. + * + * @param string $namespace + * @param string|array $hints + * @return \Illuminate\View\Factory + * @static + */ + public static function prependNamespace($namespace, $hints) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->prependNamespace($namespace, $hints); + } + + /** + * Replace the namespace hints for the given namespace. + * + * @param string $namespace + * @param string|array $hints + * @return \Illuminate\View\Factory + * @static + */ + public static function replaceNamespace($namespace, $hints) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->replaceNamespace($namespace, $hints); + } + + /** + * Register a valid view extension and its engine. + * + * @param string $extension + * @param string $engine + * @param \Closure|null $resolver + * @return void + * @static + */ + public static function addExtension($extension, $engine, $resolver = null) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->addExtension($extension, $engine, $resolver); + } + + /** + * Flush all of the factory state like sections and stacks. + * + * @return void + * @static + */ + public static function flushState() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushState(); + } + + /** + * Flush all of the section contents if done rendering. + * + * @return void + * @static + */ + public static function flushStateIfDoneRendering() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushStateIfDoneRendering(); + } + + /** + * Get the extension to engine bindings. + * + * @return array + * @static + */ + public static function getExtensions() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getExtensions(); + } + + /** + * Get the engine resolver instance. + * + * @return \Illuminate\View\Engines\EngineResolver + * @static + */ + public static function getEngineResolver() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getEngineResolver(); + } + + /** + * Get the view finder instance. + * + * @return \Illuminate\View\ViewFinderInterface + * @static + */ + public static function getFinder() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getFinder(); + } + + /** + * Set the view finder instance. + * + * @param \Illuminate\View\ViewFinderInterface $finder + * @return void + * @static + */ + public static function setFinder($finder) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->setFinder($finder); + } + + /** + * Flush the cache of views located by the finder. + * + * @return void + * @static + */ + public static function flushFinderCache() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushFinderCache(); + } + + /** + * Get the event dispatcher instance. + * + * @return \Illuminate\Contracts\Events\Dispatcher + * @static + */ + public static function getDispatcher() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getDispatcher(); + } + + /** + * Set the event dispatcher instance. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + * @static + */ + public static function setDispatcher($events) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->setDispatcher($events); + } + + /** + * Get the IoC container instance. + * + * @return \Illuminate\Contracts\Container\Container + * @static + */ + public static function getContainer() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getContainer(); + } + + /** + * Set the IoC container instance. + * + * @param \Illuminate\Contracts\Container\Container $container + * @return void + * @static + */ + public static function setContainer($container) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->setContainer($container); + } + + /** + * Get an item from the shared data. + * + * @param string $key + * @param mixed $default + * @return mixed + * @static + */ + public static function shared($key, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->shared($key, $default); + } + + /** + * Get all of the shared data for the environment. + * + * @return array + * @static + */ + public static function getShared() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getShared(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\View\Factory::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\View\Factory::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\View\Factory::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\View\Factory::flushMacros(); + } + + /** + * Start a component rendering process. + * + * @param \Illuminate\Contracts\View\View|\Illuminate\Contracts\Support\Htmlable|\Closure|string $view + * @param array $data + * @return void + * @static + */ + public static function startComponent($view, $data = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startComponent($view, $data); + } + + /** + * Get the first view that actually exists from the given list, and start a component. + * + * @param array $names + * @param array $data + * @return void + * @static + */ + public static function startComponentFirst($names, $data = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startComponentFirst($names, $data); + } + + /** + * Render the current component. + * + * @return string + * @static + */ + public static function renderComponent() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderComponent(); + } + + /** + * Get an item from the component data that exists above the current component. + * + * @param string $key + * @param mixed $default + * @return mixed|null + * @static + */ + public static function getConsumableComponentData($key, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getConsumableComponentData($key, $default); + } + + /** + * Start the slot rendering process. + * + * @param string $name + * @param string|null $content + * @param array $attributes + * @return void + * @static + */ + public static function slot($name, $content = null, $attributes = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->slot($name, $content, $attributes); + } + + /** + * Save the slot content for rendering. + * + * @return void + * @static + */ + public static function endSlot() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->endSlot(); + } + + /** + * Register a view creator event. + * + * @param array|string $views + * @param \Closure|string $callback + * @return array + * @static + */ + public static function creator($views, $callback) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->creator($views, $callback); + } + + /** + * Register multiple view composers via an array. + * + * @param array $composers + * @return array + * @static + */ + public static function composers($composers) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->composers($composers); + } + + /** + * Register a view composer event. + * + * @param array|string $views + * @param \Closure|string $callback + * @return array + * @static + */ + public static function composer($views, $callback) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->composer($views, $callback); + } + + /** + * Call the composer for a given view. + * + * @param \Illuminate\Contracts\View\View $view + * @return void + * @static + */ + public static function callComposer($view) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->callComposer($view); + } + + /** + * Call the creator for a given view. + * + * @param \Illuminate\Contracts\View\View $view + * @return void + * @static + */ + public static function callCreator($view) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->callCreator($view); + } + + /** + * Start injecting content into a fragment. + * + * @param string $fragment + * @return void + * @static + */ + public static function startFragment($fragment) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startFragment($fragment); + } + + /** + * Stop injecting content into a fragment. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopFragment() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopFragment(); + } + + /** + * Get the contents of a fragment. + * + * @param string $name + * @param string|null $default + * @return mixed + * @static + */ + public static function getFragment($name, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getFragment($name, $default); + } + + /** + * Get the entire array of rendered fragments. + * + * @return array + * @static + */ + public static function getFragments() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getFragments(); + } + + /** + * Flush all of the fragments. + * + * @return void + * @static + */ + public static function flushFragments() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushFragments(); + } + + /** + * Start injecting content into a section. + * + * @param string $section + * @param string|null $content + * @return void + * @static + */ + public static function startSection($section, $content = null) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startSection($section, $content); + } + + /** + * Inject inline content into a section. + * + * @param string $section + * @param string $content + * @return void + * @static + */ + public static function inject($section, $content) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->inject($section, $content); + } + + /** + * Stop injecting content into a section and return its contents. + * + * @return string + * @static + */ + public static function yieldSection() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->yieldSection(); + } + + /** + * Stop injecting content into a section. + * + * @param bool $overwrite + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopSection($overwrite = false) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopSection($overwrite); + } + + /** + * Stop injecting content into a section and append it. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function appendSection() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->appendSection(); + } + + /** + * Get the string contents of a section. + * + * @param string $section + * @param string $default + * @return string + * @static + */ + public static function yieldContent($section, $default = '') + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->yieldContent($section, $default); + } + + /** + * Get the parent placeholder for the current request. + * + * @param string $section + * @return string + * @static + */ + public static function parentPlaceholder($section = '') + { + return \Illuminate\View\Factory::parentPlaceholder($section); + } + + /** + * Check if section exists. + * + * @param string $name + * @return bool + * @static + */ + public static function hasSection($name) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->hasSection($name); + } + + /** + * Check if section does not exist. + * + * @param string $name + * @return bool + * @static + */ + public static function sectionMissing($name) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->sectionMissing($name); + } + + /** + * Get the contents of a section. + * + * @param string $name + * @param string|null $default + * @return mixed + * @static + */ + public static function getSection($name, $default = null) + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getSection($name, $default); + } + + /** + * Get the entire array of sections. + * + * @return array + * @static + */ + public static function getSections() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getSections(); + } + + /** + * Flush all of the sections. + * + * @return void + * @static + */ + public static function flushSections() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushSections(); + } + + /** + * Add new loop to the stack. + * + * @param \Countable|array $data + * @return void + * @static + */ + public static function addLoop($data) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->addLoop($data); + } + + /** + * Increment the top loop's indices. + * + * @return void + * @static + */ + public static function incrementLoopIndices() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->incrementLoopIndices(); + } + + /** + * Pop a loop from the top of the loop stack. + * + * @return void + * @static + */ + public static function popLoop() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->popLoop(); + } + + /** + * Get an instance of the last loop in the stack. + * + * @return \stdClass|null + * @static + */ + public static function getLastLoop() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getLastLoop(); + } + + /** + * Get the entire loop stack. + * + * @return array + * @static + */ + public static function getLoopStack() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->getLoopStack(); + } + + /** + * Start injecting content into a push section. + * + * @param string $section + * @param string $content + * @return void + * @static + */ + public static function startPush($section, $content = '') + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startPush($section, $content); + } + + /** + * Stop injecting content into a push section. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopPush() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopPush(); + } + + /** + * Start prepending content into a push section. + * + * @param string $section + * @param string $content + * @return void + * @static + */ + public static function startPrepend($section, $content = '') + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startPrepend($section, $content); + } + + /** + * Stop prepending content into a push section. + * + * @return string + * @throws \InvalidArgumentException + * @static + */ + public static function stopPrepend() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->stopPrepend(); + } + + /** + * Get the string contents of a push section. + * + * @param string $section + * @param string $default + * @return string + * @static + */ + public static function yieldPushContent($section, $default = '') + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->yieldPushContent($section, $default); + } + + /** + * Flush all of the stacks. + * + * @return void + * @static + */ + public static function flushStacks() + { + /** @var \Illuminate\View\Factory $instance */ + $instance->flushStacks(); + } + + /** + * Start a translation block. + * + * @param array $replacements + * @return void + * @static + */ + public static function startTranslation($replacements = []) + { + /** @var \Illuminate\View\Factory $instance */ + $instance->startTranslation($replacements); + } + + /** + * Render the current translation. + * + * @return string + * @static + */ + public static function renderTranslation() + { + /** @var \Illuminate\View\Factory $instance */ + return $instance->renderTranslation(); + } + + } + /** + * + * + * @see \Illuminate\Foundation\Vite + */ + class Vite { + /** + * Get the preloaded assets. + * + * @return array + * @static + */ + public static function preloadedAssets() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->preloadedAssets(); + } + + /** + * Get the Content Security Policy nonce applied to all generated tags. + * + * @return string|null + * @static + */ + public static function cspNonce() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->cspNonce(); + } + + /** + * Generate or set a Content Security Policy nonce to apply to all generated tags. + * + * @param string|null $nonce + * @return string + * @static + */ + public static function useCspNonce($nonce = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useCspNonce($nonce); + } + + /** + * Use the given key to detect integrity hashes in the manifest. + * + * @param string|false $key + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useIntegrityKey($key) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useIntegrityKey($key); + } + + /** + * Set the Vite entry points. + * + * @param array $entryPoints + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function withEntryPoints($entryPoints) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->withEntryPoints($entryPoints); + } + + /** + * Merge additional Vite entry points with the current set. + * + * @param array $entryPoints + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function mergeEntryPoints($entryPoints) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->mergeEntryPoints($entryPoints); + } + + /** + * Set the filename for the manifest file. + * + * @param string $filename + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useManifestFilename($filename) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useManifestFilename($filename); + } + + /** + * Resolve asset paths using the provided resolver. + * + * @param callable|null $resolver + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function createAssetPathsUsing($resolver) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->createAssetPathsUsing($resolver); + } + + /** + * Get the Vite "hot" file path. + * + * @return string + * @static + */ + public static function hotFile() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->hotFile(); + } + + /** + * Set the Vite "hot" file path. + * + * @param string $path + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useHotFile($path) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useHotFile($path); + } + + /** + * Set the Vite build directory. + * + * @param string $path + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useBuildDirectory($path) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useBuildDirectory($path); + } + + /** + * Use the given callback to resolve attributes for script tags. + * + * @param (callable(string, string, ?array, ?array): array)|array $attributes + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useScriptTagAttributes($attributes) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useScriptTagAttributes($attributes); + } + + /** + * Use the given callback to resolve attributes for style tags. + * + * @param (callable(string, string, ?array, ?array): array)|array $attributes + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useStyleTagAttributes($attributes) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useStyleTagAttributes($attributes); + } + + /** + * Use the given callback to resolve attributes for preload tags. + * + * @param (callable(string, string, ?array, ?array): (array|false))|array|false $attributes + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function usePreloadTagAttributes($attributes) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->usePreloadTagAttributes($attributes); + } + + /** + * Eagerly prefetch assets. + * + * @param int|null $concurrency + * @param string $event + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function prefetch($concurrency = null, $event = 'load') + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->prefetch($concurrency, $event); + } + + /** + * Use the "waterfall" prefetching strategy. + * + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useWaterfallPrefetching($concurrency = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useWaterfallPrefetching($concurrency); + } + + /** + * Use the "aggressive" prefetching strategy. + * + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function useAggressivePrefetching() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->useAggressivePrefetching(); + } + + /** + * Set the prefetching strategy. + * + * @param 'waterfall'|'aggressive'|null $strategy + * @param array $config + * @return \Illuminate\Foundation\Vite + * @static + */ + public static function usePrefetchStrategy($strategy, $config = []) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->usePrefetchStrategy($strategy, $config); + } + + /** + * Generate React refresh runtime script. + * + * @return \Illuminate\Support\HtmlString|void + * @static + */ + public static function reactRefresh() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->reactRefresh(); + } + + /** + * Get the URL for an asset. + * + * @param string $asset + * @param string|null $buildDirectory + * @return string + * @static + */ + public static function asset($asset, $buildDirectory = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->asset($asset, $buildDirectory); + } + + /** + * Get the content of a given asset. + * + * @param string $asset + * @param string|null $buildDirectory + * @return string + * @throws \Illuminate\Foundation\ViteException + * @static + */ + public static function content($asset, $buildDirectory = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->content($asset, $buildDirectory); + } + + /** + * Get a unique hash representing the current manifest, or null if there is no manifest. + * + * @param string|null $buildDirectory + * @return string|null + * @static + */ + public static function manifestHash($buildDirectory = null) + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->manifestHash($buildDirectory); + } + + /** + * Determine if the HMR server is running. + * + * @return bool + * @static + */ + public static function isRunningHot() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->isRunningHot(); + } + + /** + * Get the Vite tag content as a string of HTML. + * + * @return string + * @static + */ + public static function toHtml() + { + /** @var \Illuminate\Foundation\Vite $instance */ + return $instance->toHtml(); + } + + /** + * Flush state. + * + * @return void + * @static + */ + public static function flush() + { + /** @var \Illuminate\Foundation\Vite $instance */ + $instance->flush(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Foundation\Vite::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Foundation\Vite::mixin($mixin, $replace); + } + + /** + * Checks if macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + return \Illuminate\Foundation\Vite::hasMacro($name); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Foundation\Vite::flushMacros(); + } + + } + } + +namespace Illuminate\Http { + /** + * + * + */ + class Request { + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestValidation() + * @param array $rules + * @param mixed $params + * @static + */ + public static function validate($rules, ...$params) + { + return \Illuminate\Http\Request::validate($rules, ...$params); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestValidation() + * @param string $errorBag + * @param array $rules + * @param mixed $params + * @static + */ + public static function validateWithBag($errorBag, $rules, ...$params) + { + return \Illuminate\Http\Request::validateWithBag($errorBag, $rules, ...$params); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @param mixed $absolute + * @static + */ + public static function hasValidSignature($absolute = true) + { + return \Illuminate\Http\Request::hasValidSignature($absolute); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @static + */ + public static function hasValidRelativeSignature() + { + return \Illuminate\Http\Request::hasValidRelativeSignature(); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @param mixed $ignoreQuery + * @param mixed $absolute + * @static + */ + public static function hasValidSignatureWhileIgnoring($ignoreQuery = [], $absolute = true) + { + return \Illuminate\Http\Request::hasValidSignatureWhileIgnoring($ignoreQuery, $absolute); + } + + /** + * + * + * @see \Illuminate\Foundation\Providers\FoundationServiceProvider::registerRequestSignatureValidation() + * @param mixed $ignoreQuery + * @static + */ + public static function hasValidRelativeSignatureWhileIgnoring($ignoreQuery = []) + { + return \Illuminate\Http\Request::hasValidRelativeSignatureWhileIgnoring($ignoreQuery); + } + + } + } + + +namespace { + class App extends \Illuminate\Support\Facades\App {} + class Arr extends \Illuminate\Support\Arr {} + class Artisan extends \Illuminate\Support\Facades\Artisan {} + class Auth extends \Illuminate\Support\Facades\Auth {} + class Blade extends \Illuminate\Support\Facades\Blade {} + class Broadcast extends \Illuminate\Support\Facades\Broadcast {} + class Bus extends \Illuminate\Support\Facades\Bus {} + class Cache extends \Illuminate\Support\Facades\Cache {} + class Concurrency extends \Illuminate\Support\Facades\Concurrency {} + class Config extends \Illuminate\Support\Facades\Config {} + class Context extends \Illuminate\Support\Facades\Context {} + class Cookie extends \Illuminate\Support\Facades\Cookie {} + class Crypt extends \Illuminate\Support\Facades\Crypt {} + class Date extends \Illuminate\Support\Facades\Date {} + class DB extends \Illuminate\Support\Facades\DB {} + + /** + * + * + * @template TCollection of static + * @template TModel of static + * @template TValue of static + * @template TValue of static + */ + class Eloquent extends \Illuminate\Database\Eloquent\Model { /** + * Create and return an un-saved model instance. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function make($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->make($attributes); + } + + /** + * Register a new global scope. + * + * @param string $identifier + * @param \Illuminate\Database\Eloquent\Scope|\Closure $scope + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withGlobalScope($identifier, $scope) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withGlobalScope($identifier, $scope); + } + + /** + * Remove a registered global scope. + * + * @param \Illuminate\Database\Eloquent\Scope|string $scope + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutGlobalScope($scope) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutGlobalScope($scope); + } + + /** + * Remove all or passed registered global scopes. + * + * @param array|null $scopes + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutGlobalScopes($scopes = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutGlobalScopes($scopes); + } + + /** + * Get an array of global scopes that were removed from the query. + * + * @return array + * @static + */ + public static function removedScopes() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->removedScopes(); + } + + /** + * Add a where clause on the primary key to the query. + * + * @param mixed $id + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereKey($id) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereKey($id); + } + + /** + * Add a where clause on the primary key to the query. + * + * @param mixed $id + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereKeyNot($id) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereKeyNot($id); + } + + /** + * Add a basic where clause to the query. + * + * @param (\Closure(static): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function where($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->where($column, $operator, $value, $boolean); + } + + /** + * Add a basic where clause to the query, and return the first result. + * + * @param (\Closure(static): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return TModel|null + * @static + */ + public static function firstWhere($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstWhere($column, $operator, $value, $boolean); + } + + /** + * Add an "or where" clause to the query. + * + * @param (\Closure(static): mixed)|array|string|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhere($column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhere($column, $operator, $value); + } + + /** + * Add a basic "where not" clause to the query. + * + * @param (\Closure(static): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNot($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereNot($column, $operator, $value, $boolean); + } + + /** + * Add an "or where not" clause to the query. + * + * @param (\Closure(static): mixed)|array|string|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNot($column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereNot($column, $operator, $value); + } + + /** + * Add an "order by" clause for a timestamp to the query. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function latest($column = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->latest($column); + } + + /** + * Add an "order by" clause for a timestamp to the query. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function oldest($column = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->oldest($column); + } + + /** + * Create a collection of models from plain arrays. + * + * @param array $items + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function hydrate($items) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->hydrate($items); + } + + /** + * Insert into the database after merging the model's default attributes, setting timestamps, and casting values. + * + * @param array> $values + * @return bool + * @static + */ + public static function fillAndInsert($values) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->fillAndInsert($values); + } + + /** + * Insert (ignoring errors) into the database after merging the model's default attributes, setting timestamps, and casting values. + * + * @param array> $values + * @return int + * @static + */ + public static function fillAndInsertOrIgnore($values) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->fillAndInsertOrIgnore($values); + } + + /** + * Insert a record into the database and get its ID after merging the model's default attributes, setting timestamps, and casting values. + * + * @param array $values + * @return int + * @static + */ + public static function fillAndInsertGetId($values) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->fillAndInsertGetId($values); + } + + /** + * Enrich the given values by merging in the model's default attributes, adding timestamps, and casting values. + * + * @param array> $values + * @return array> + * @static + */ + public static function fillForInsert($values) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->fillForInsert($values); + } + + /** + * Create a collection of models from a raw query. + * + * @param string $query + * @param array $bindings + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function fromQuery($query, $bindings = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->fromQuery($query, $bindings); + } + + /** + * Find a model by its primary key. + * + * @param mixed $id + * @param array|string $columns + * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TModel|null) + * @static + */ + public static function find($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->find($id, $columns); + } + + /** + * Find a sole model by its primary key. + * + * @param mixed $id + * @param array|string $columns + * @return TModel + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function findSole($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findSole($id, $columns); + } + + /** + * Find multiple models by their primary keys. + * + * @param \Illuminate\Contracts\Support\Arrayable|array $ids + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function findMany($ids, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findMany($ids, $columns); + } + + /** + * Find a model by its primary key or throw an exception. + * + * @param mixed $id + * @param array|string $columns + * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TModel) + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @static + */ + public static function findOrFail($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findOrFail($id, $columns); + } + + /** + * Find a model by its primary key or return fresh model instance. + * + * @param mixed $id + * @param array|string $columns + * @return ($id is (\Illuminate\Contracts\Support\Arrayable|array) ? \Illuminate\Database\Eloquent\Collection : TModel) + * @static + */ + public static function findOrNew($id, $columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findOrNew($id, $columns); + } + + /** + * Find a model by its primary key or call a callback. + * + * @template TValue + * @param mixed $id + * @param (\Closure(): TValue)|list|string $columns + * @param (\Closure(): TValue)|null $callback + * @return ( $id is (\Illuminate\Contracts\Support\Arrayable|array) + * ? \Illuminate\Database\Eloquent\Collection + * : TModel|TValue + * ) + * @static + */ + public static function findOr($id, $columns = [], $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->findOr($id, $columns, $callback); + } + + /** + * Get the first record matching the attributes or instantiate it. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function firstOrNew($attributes = [], $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOrNew($attributes, $values); + } + + /** + * Get the first record matching the attributes. If the record is not found, create it. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function firstOrCreate($attributes = [], $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOrCreate($attributes, $values); + } + + /** + * Attempt to create the record. If a unique constraint violation occurs, attempt to find the matching record. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function createOrFirst($attributes = [], $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->createOrFirst($attributes, $values); + } + + /** + * Create or update a record matching the attributes, and fill it with values. + * + * @param array $attributes + * @param array $values + * @return TModel + * @static + */ + public static function updateOrCreate($attributes, $values = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->updateOrCreate($attributes, $values); + } + + /** + * Create a record matching the attributes, or increment the existing record. + * + * @param array $attributes + * @param string $column + * @param int|float $default + * @param int|float $step + * @param array $extra + * @return TModel + * @static + */ + public static function incrementOrCreate($attributes, $column = 'count', $default = 1, $step = 1, $extra = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->incrementOrCreate($attributes, $column, $default, $step, $extra); + } + + /** + * Execute the query and get the first result or throw an exception. + * + * @param array|string $columns + * @return TModel + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @static + */ + public static function firstOrFail($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOrFail($columns); + } + + /** + * Execute the query and get the first result or call a callback. + * + * @template TValue + * @param (\Closure(): TValue)|list $columns + * @param (\Closure(): TValue)|null $callback + * @return TModel|TValue + * @static + */ + public static function firstOr($columns = [], $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->firstOr($columns, $callback); + } + + /** + * Execute the query and get the first result if it's the sole matching record. + * + * @param array|string $columns + * @return TModel + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function sole($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->sole($columns); + } + + /** + * Get a single column's value from the first result of a query. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return mixed + * @static + */ + public static function value($column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->value($column); + } + + /** + * Get a single column's value from the first result of a query if it's the sole matching record. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return mixed + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function soleValue($column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->soleValue($column); + } + + /** + * Get a single column's value from the first result of the query or throw an exception. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @return mixed + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * @static + */ + public static function valueOrFail($column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->valueOrFail($column); + } + + /** + * Execute the query as a "select" statement. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Collection + * @static + */ + public static function get($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->get($columns); + } + + /** + * Get the hydrated models without eager loading. + * + * @param array|string $columns + * @return array + * @static + */ + public static function getModels($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getModels($columns); + } + + /** + * Eager load the relationships for the models. + * + * @param array $models + * @return array + * @static + */ + public static function eagerLoadRelations($models) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->eagerLoadRelations($models); + } + + /** + * Register a closure to be invoked after the query is executed. + * + * @param \Closure $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function afterQuery($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->afterQuery($callback); + } + + /** + * Invoke the "after query" modification callbacks. + * + * @param mixed $result + * @return mixed + * @static + */ + public static function applyAfterQueryCallbacks($result) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->applyAfterQueryCallbacks($result); + } + + /** + * Get a lazy collection for the given query. + * + * @return \Illuminate\Support\LazyCollection + * @static + */ + public static function cursor() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->cursor(); + } + + /** + * Get a collection with the values of a given column. + * + * @param string|\Illuminate\Contracts\Database\Query\Expression $column + * @param string|null $key + * @return \Illuminate\Support\Collection + * @static + */ + public static function pluck($column, $key = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->pluck($column, $key); + } + + /** + * Paginate the given query. + * + * @param int|null|\Closure $perPage + * @param array|string $columns + * @param string $pageName + * @param int|null $page + * @param \Closure|int|null $total + * @return \Illuminate\Pagination\LengthAwarePaginator + * @throws \InvalidArgumentException + * @static + */ + public static function paginate($perPage = null, $columns = [], $pageName = 'page', $page = null, $total = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->paginate($perPage, $columns, $pageName, $page, $total); + } + + /** + * Paginate the given query into a simple paginator. + * + * @param int|null $perPage + * @param array|string $columns + * @param string $pageName + * @param int|null $page + * @return \Illuminate\Contracts\Pagination\Paginator + * @static + */ + public static function simplePaginate($perPage = null, $columns = [], $pageName = 'page', $page = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->simplePaginate($perPage, $columns, $pageName, $page); + } + + /** + * Paginate the given query into a cursor paginator. + * + * @param int|null $perPage + * @param array|string $columns + * @param string $cursorName + * @param \Illuminate\Pagination\Cursor|string|null $cursor + * @return \Illuminate\Contracts\Pagination\CursorPaginator + * @static + */ + public static function cursorPaginate($perPage = null, $columns = [], $cursorName = 'cursor', $cursor = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->cursorPaginate($perPage, $columns, $cursorName, $cursor); + } + + /** + * Save a new model and return the instance. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function create($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->create($attributes); + } + + /** + * Save a new model and return the instance without raising model events. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function createQuietly($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->createQuietly($attributes); + } + + /** + * Save a new model and return the instance. Allow mass-assignment. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function forceCreate($attributes) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->forceCreate($attributes); + } + + /** + * Save a new model instance with mass assignment without raising model events. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function forceCreateQuietly($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->forceCreateQuietly($attributes); + } + + /** + * Insert new records or update the existing ones. + * + * @param array $values + * @param array|string $uniqueBy + * @param array|null $update + * @return int + * @static + */ + public static function upsert($values, $uniqueBy, $update = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->upsert($values, $uniqueBy, $update); + } + + /** + * Register a replacement for the default delete function. + * + * @param \Closure $callback + * @return void + * @static + */ + public static function onDelete($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + $instance->onDelete($callback); + } + + /** + * Call the given local model scopes. + * + * @param array|string $scopes + * @return static|mixed + * @static + */ + public static function scopes($scopes) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->scopes($scopes); + } + + /** + * Apply the scopes to the Eloquent builder instance and return it. + * + * @return static + * @static + */ + public static function applyScopes() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->applyScopes(); + } + + /** + * Prevent the specified relations from being eager loaded. + * + * @param mixed $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function without($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->without($relations); + } + + /** + * Set the relationships that should be eager loaded while removing any previously added eager loading specifications. + * + * @param array): mixed)|string>|string $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withOnly($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withOnly($relations); + } + + /** + * Create a new instance of the model being queried. + * + * @param array $attributes + * @return TModel + * @static + */ + public static function newModelInstance($attributes = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->newModelInstance($attributes); + } + + /** + * Specify attributes that should be added to any new models created by this builder. + * + * The given key / value pairs will also be added as where conditions to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|array|string $attributes + * @param mixed $value + * @param bool $asConditions + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withAttributes($attributes, $value = null, $asConditions = true) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withAttributes($attributes, $value, $asConditions); + } + + /** + * Apply query-time casts to the model instance. + * + * @param array $casts + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withCasts($casts) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withCasts($casts); + } + + /** + * Execute the given Closure within a transaction savepoint if needed. + * + * @template TModelValue + * @param \Closure(): TModelValue $scope + * @return TModelValue + * @static + */ + public static function withSavepointIfNeeded($scope) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withSavepointIfNeeded($scope); + } + + /** + * Get the underlying query builder instance. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function getQuery() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getQuery(); + } + + /** + * Set the underlying query builder instance. + * + * @param \Illuminate\Database\Query\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function setQuery($query) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->setQuery($query); + } + + /** + * Get a base query builder instance. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function toBase() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->toBase(); + } + + /** + * Get the relationships being eagerly loaded. + * + * @return array + * @static + */ + public static function getEagerLoads() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getEagerLoads(); + } + + /** + * Set the relationships being eagerly loaded. + * + * @param array $eagerLoad + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function setEagerLoads($eagerLoad) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->setEagerLoads($eagerLoad); + } + + /** + * Indicate that the given relationships should not be eagerly loaded. + * + * @param array $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutEagerLoad($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutEagerLoad($relations); + } + + /** + * Flush the relationships being eagerly loaded. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withoutEagerLoads() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withoutEagerLoads(); + } + + /** + * Get the "limit" value from the query or null if it's not set. + * + * @return mixed + * @static + */ + public static function getLimit() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getLimit(); + } + + /** + * Get the "offset" value from the query or null if it's not set. + * + * @return mixed + * @static + */ + public static function getOffset() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getOffset(); + } + + /** + * Get the model instance being queried. + * + * @return TModel + * @static + */ + public static function getModel() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getModel(); + } + + /** + * Set a model instance for the model being queried. + * + * @template TModelNew of \Illuminate\Database\Eloquent\Model + * @param TModelNew $model + * @return static + * @static + */ + public static function setModel($model) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->setModel($model); + } + + /** + * Get the given macro by name. + * + * @param string $name + * @return \Closure + * @static + */ + public static function getMacro($name) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->getMacro($name); + } + + /** + * Checks if a macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasMacro($name) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->hasMacro($name); + } + + /** + * Get the given global macro by name. + * + * @param string $name + * @return \Closure + * @static + */ + public static function getGlobalMacro($name) + { + return \Illuminate\Database\Eloquent\Builder::getGlobalMacro($name); + } + + /** + * Checks if a global macro is registered. + * + * @param string $name + * @return bool + * @static + */ + public static function hasGlobalMacro($name) + { + return \Illuminate\Database\Eloquent\Builder::hasGlobalMacro($name); + } + + /** + * Clone the Eloquent query builder. + * + * @return static + * @static + */ + public static function clone() + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->clone(); + } + + /** + * Register a closure to be invoked on a clone. + * + * @param \Closure $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function onClone($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->onClone($callback); + } + + /** + * Chunk the results of the query. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @return bool + * @static + */ + public static function chunk($count, $callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunk($count, $callback); + } + + /** + * Run a map over each item while chunking. + * + * @template TReturn + * @param callable(TValue): TReturn $callback + * @param int $count + * @return \Illuminate\Support\Collection + * @static + */ + public static function chunkMap($callback, $count = 1000) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunkMap($callback, $count); + } + + /** + * Execute a callback over each item while chunking. + * + * @param callable(TValue, int): mixed $callback + * @param int $count + * @return bool + * @throws \RuntimeException + * @static + */ + public static function each($callback, $count = 1000) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->each($callback, $count); + } + + /** + * Chunk the results of a query by comparing IDs. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @param string|null $column + * @param string|null $alias + * @return bool + * @static + */ + public static function chunkById($count, $callback, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunkById($count, $callback, $column, $alias); + } + + /** + * Chunk the results of a query by comparing IDs in descending order. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @param string|null $column + * @param string|null $alias + * @return bool + * @static + */ + public static function chunkByIdDesc($count, $callback, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->chunkByIdDesc($count, $callback, $column, $alias); + } + + /** + * Chunk the results of a query by comparing IDs in a given order. + * + * @param int $count + * @param callable(\Illuminate\Support\Collection, int): mixed $callback + * @param string|null $column + * @param string|null $alias + * @param bool $descending + * @return bool + * @throws \RuntimeException + * @static + */ + public static function orderedChunkById($count, $callback, $column = null, $alias = null, $descending = false) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orderedChunkById($count, $callback, $column, $alias, $descending); + } + + /** + * Execute a callback over each item while chunking by ID. + * + * @param callable(TValue, int): mixed $callback + * @param int $count + * @param string|null $column + * @param string|null $alias + * @return bool + * @static + */ + public static function eachById($callback, $count = 1000, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->eachById($callback, $count, $column, $alias); + } + + /** + * Query lazily, by chunks of the given size. + * + * @param int $chunkSize + * @return \Illuminate\Support\LazyCollection + * @throws \InvalidArgumentException + * @static + */ + public static function lazy($chunkSize = 1000) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->lazy($chunkSize); + } + + /** + * Query lazily, by chunking the results of a query by comparing IDs. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + * @throws \InvalidArgumentException + * @static + */ + public static function lazyById($chunkSize = 1000, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->lazyById($chunkSize, $column, $alias); + } + + /** + * Query lazily, by chunking the results of a query by comparing IDs in descending order. + * + * @param int $chunkSize + * @param string|null $column + * @param string|null $alias + * @return \Illuminate\Support\LazyCollection + * @throws \InvalidArgumentException + * @static + */ + public static function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->lazyByIdDesc($chunkSize, $column, $alias); + } + + /** + * Execute the query and get the first result. + * + * @param array|string $columns + * @return TValue|null + * @static + */ + public static function first($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->first($columns); + } + + /** + * Execute the query and get the first result if it's the sole matching record. + * + * @param array|string $columns + * @return TValue + * @throws \Illuminate\Database\RecordsNotFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + * @static + */ + public static function baseSole($columns = []) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->baseSole($columns); + } + + /** + * Pass the query to a given callback and then return it. + * + * @param callable($this): mixed $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function tap($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->tap($callback); + } + + /** + * Pass the query to a given callback and return the result. + * + * @template TReturn + * @param (callable($this): TReturn) $callback + * @return (TReturn is null|void ? $this : TReturn) + * @static + */ + public static function pipe($callback) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->pipe($callback); + } + + /** + * Apply the callback if the given "value" is (or resolves to) truthy. + * + * @template TWhenParameter + * @template TWhenReturnType + * @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback + * @param (callable($this, TWhenParameter): TWhenReturnType)|null $default + * @return $this|TWhenReturnType + * @static + */ + public static function when($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->when($value, $callback, $default); + } + + /** + * Apply the callback if the given "value" is (or resolves to) falsy. + * + * @template TUnlessParameter + * @template TUnlessReturnType + * @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback + * @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default + * @return $this|TUnlessReturnType + * @static + */ + public static function unless($value = null, $callback = null, $default = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->unless($value, $callback, $default); + } + + /** + * Add a relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param string $operator + * @param int $count + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @throws \RuntimeException + * @static + */ + public static function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->has($relation, $operator, $count, $boolean, $callback); + } + + /** + * Add a relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\Relation<*, *, *>|string $relation + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHas($relation, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orHas($relation, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function doesntHave($relation, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->doesntHave($relation, $boolean, $callback); + } + + /** + * Add a relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\Relation<*, *, *>|string $relation + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orDoesntHave($relation) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orDoesntHave($relation); + } + + /** + * Add a relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereHas($relation, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereHas($relation, $callback, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query with where clauses. + * + * Also load the relationship with the same condition. + * + * @param string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Database\Eloquent\Relations\Relation<*, *, *>): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withWhereHas($relation, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withWhereHas($relation, $callback, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereHas($relation, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereHas($relation, $callback, $operator, $count); + } + + /** + * Add a relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDoesntHave($relation, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereDoesntHave($relation, $callback); + } + + /** + * Add a relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDoesntHave($relation, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereDoesntHave($relation, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param string $operator + * @param int $count + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->hasMorph($relation, $types, $operator, $count, $boolean, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param string|array $types + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHasMorph($relation, $types, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orHasMorph($relation, $types, $operator, $count); + } + + /** + * Add a polymorphic relationship count / exists condition to the query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param string $boolean + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function doesntHaveMorph($relation, $types, $boolean = 'and', $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->doesntHaveMorph($relation, $types, $boolean, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with an "or". + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param string|array $types + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orDoesntHaveMorph($relation, $types) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orDoesntHaveMorph($relation, $types); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereHasMorph($relation, $types, $callback, $operator, $count); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @param string $operator + * @param int $count + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereHasMorph($relation, $types, $callback = null, $operator = '>=', $count = 1) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereHasMorph($relation, $types, $callback, $operator, $count); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDoesntHaveMorph($relation, $types, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereDoesntHaveMorph($relation, $types, $callback); + } + + /** + * Add a polymorphic relationship count / exists condition to the query with where clauses and an "or". + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder, string): mixed)|null $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDoesntHaveMorph($relation, $types, $callback = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereDoesntHaveMorph($relation, $types, $callback); + } + + /** + * Add a basic where clause to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereRelation($relation, $column, $operator, $value); + } + + /** + * Add a basic where clause to a relationship query and eager-load the relationship with the same conditions. + * + * @param \Illuminate\Database\Eloquent\Relations\Relation<*, *, *>|string $relation + * @param \Closure|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withWhereRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withWhereRelation($relation, $column, $operator, $value); + } + + /** + * Add an "or where" clause to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereRelation($relation, $column, $operator, $value); + } + + /** + * Add a basic count / exists condition to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDoesntHaveRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereDoesntHaveRelation($relation, $column, $operator, $value); + } + + /** + * Add an "or where" clause to a relationship query. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\Relation|string $relation + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDoesntHaveRelation($relation, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereDoesntHaveRelation($relation, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with a where clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMorphRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereMorphRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with an "or where" clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMorphRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereMorphRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with a doesn't have clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMorphDoesntHaveRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereMorphDoesntHaveRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a polymorphic relationship condition to the query with an "or doesn't have" clause. + * + * @template TRelatedModel of \Illuminate\Database\Eloquent\Model + * @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation + * @param string|array $types + * @param (\Closure(\Illuminate\Database\Eloquent\Builder): mixed)|string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMorphDoesntHaveRelation($relation, $types, $column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereMorphDoesntHaveRelation($relation, $types, $column, $operator, $value); + } + + /** + * Add a morph-to relationship condition to the query. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string|null $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMorphedTo($relation, $model, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereMorphedTo($relation, $model, $boolean); + } + + /** + * Add a not morph-to relationship condition to the query. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotMorphedTo($relation, $model, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereNotMorphedTo($relation, $model, $boolean); + } + + /** + * Add a morph-to relationship condition to the query with an "or where" clause. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string|null $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMorphedTo($relation, $model) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereMorphedTo($relation, $model); + } + + /** + * Add a not morph-to relationship condition to the query with an "or where" clause. + * + * @param \Illuminate\Database\Eloquent\Relations\MorphTo<*, *>|string $relation + * @param \Illuminate\Database\Eloquent\Model|iterable|string $model + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotMorphedTo($relation, $model) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereNotMorphedTo($relation, $model); + } + + /** + * Add a "belongs to" relationship where clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection $related + * @param string|null $relationshipName + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @throws \Illuminate\Database\Eloquent\RelationNotFoundException + * @static + */ + public static function whereBelongsTo($related, $relationshipName = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereBelongsTo($related, $relationshipName, $boolean); + } + + /** + * Add a "BelongsTo" relationship with an "or where" clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model $related + * @param string|null $relationshipName + * @return \Illuminate\Database\Eloquent\Builder + * @throws \RuntimeException + * @static + */ + public static function orWhereBelongsTo($related, $relationshipName = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereBelongsTo($related, $relationshipName); + } + + /** + * Add a "belongs to many" relationship where clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection $related + * @param string|null $relationshipName + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @throws \Illuminate\Database\Eloquent\RelationNotFoundException + * @static + */ + public static function whereAttachedTo($related, $relationshipName = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->whereAttachedTo($related, $relationshipName, $boolean); + } + + /** + * Add a "belongs to many" relationship with an "or where" clause to the query. + * + * @param \Illuminate\Database\Eloquent\Model $related + * @param string|null $relationshipName + * @return \Illuminate\Database\Eloquent\Builder + * @throws \RuntimeException + * @static + */ + public static function orWhereAttachedTo($related, $relationshipName = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->orWhereAttachedTo($related, $relationshipName); + } + + /** + * Add subselect queries to include an aggregate value for a relationship. + * + * @param mixed $relations + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $function + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withAggregate($relations, $column, $function = null) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withAggregate($relations, $column, $function); + } + + /** + * Add subselect queries to count the relations. + * + * @param mixed $relations + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withCount($relations) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withCount($relations); + } + + /** + * Add subselect queries to include the max of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withMax($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withMax($relation, $column); + } + + /** + * Add subselect queries to include the min of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withMin($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withMin($relation, $column); + } + + /** + * Add subselect queries to include the sum of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withSum($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withSum($relation, $column); + } + + /** + * Add subselect queries to include the average of the relation's column. + * + * @param string|array $relation + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withAvg($relation, $column) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withAvg($relation, $column); + } + + /** + * Add subselect queries to include the existence of related models. + * + * @param string|array $relation + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function withExists($relation) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->withExists($relation); + } + + /** + * Merge the where constraints from another query to the current query. + * + * @param \Illuminate\Database\Eloquent\Builder<*> $from + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function mergeConstraintsFrom($from) + { + /** @var \Illuminate\Database\Eloquent\Builder $instance */ + return $instance->mergeConstraintsFrom($from); + } + + /** + * Set the columns to be selected. + * + * @param array|mixed $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function select($columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->select($columns); + } + + /** + * Add a subselect expression to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function selectSub($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->selectSub($query, $as); + } + + /** + * Add a new "raw" select expression to the query. + * + * @param string $expression + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function selectRaw($expression, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->selectRaw($expression, $bindings); + } + + /** + * Makes "from" fetch from a subquery. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function fromSub($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->fromSub($query, $as); + } + + /** + * Add a raw from clause to the query. + * + * @param string $expression + * @param mixed $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function fromRaw($expression, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->fromRaw($expression, $bindings); + } + + /** + * Add a new select column to the query. + * + * @param array|mixed $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addSelect($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addSelect($column); + } + + /** + * Force the query to only return distinct results. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function distinct() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->distinct(); + } + + /** + * Set the table which the query is targeting. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Contracts\Database\Query\Expression|string $table + * @param string|null $as + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function from($table, $as = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->from($table, $as); + } + + /** + * Add an index hint to suggest a query index. + * + * @param string $index + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function useIndex($index) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->useIndex($index); + } + + /** + * Add an index hint to force a query index. + * + * @param string $index + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forceIndex($index) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forceIndex($index); + } + + /** + * Add an index hint to ignore a query index. + * + * @param string $index + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function ignoreIndex($index) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->ignoreIndex($index); + } + + /** + * Add a join clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @param string $type + * @param bool $where + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->join($table, $first, $operator, $second, $type, $where); + } + + /** + * Add a "join where" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string $second + * @param string $type + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function joinWhere($table, $first, $operator, $second, $type = 'inner') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->joinWhere($table, $first, $operator, $second, $type); + } + + /** + * Add a subquery join clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @param string $type + * @param bool $where + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->joinSub($query, $as, $first, $operator, $second, $type, $where); + } + + /** + * Add a lateral join clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function joinLateral($query, $as, $type = 'inner') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->joinLateral($query, $as, $type); + } + + /** + * Add a lateral left join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoinLateral($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoinLateral($query, $as); + } + + /** + * Add a left join to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoin($table, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoin($table, $first, $operator, $second); + } + + /** + * Add a "join where" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoinWhere($table, $first, $operator, $second) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoinWhere($table, $first, $operator, $second); + } + + /** + * Add a subquery left join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function leftJoinSub($query, $as, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->leftJoinSub($query, $as, $first, $operator, $second); + } + + /** + * Add a right join to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function rightJoin($table, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rightJoin($table, $first, $operator, $second); + } + + /** + * Add a "right join where" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function rightJoinWhere($table, $first, $operator, $second) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rightJoinWhere($table, $first, $operator, $second); + } + + /** + * Add a subquery right join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function rightJoinSub($query, $as, $first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rightJoinSub($query, $as, $first, $operator, $second); + } + + /** + * Add a "cross join" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $table + * @param \Closure|\Illuminate\Contracts\Database\Query\Expression|string|null $first + * @param string|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function crossJoin($table, $first = null, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->crossJoin($table, $first, $operator, $second); + } + + /** + * Add a subquery cross join to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @param string $as + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function crossJoinSub($query, $as) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->crossJoinSub($query, $as); + } + + /** + * Merge an array of where clauses and bindings. + * + * @param array $wheres + * @param array $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function mergeWheres($wheres, $bindings) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->mergeWheres($wheres, $bindings); + } + + /** + * Prepare the value and operator for a where clause. + * + * @param string $value + * @param string $operator + * @param bool $useDefault + * @return array + * @throws \InvalidArgumentException + * @static + */ + public static function prepareValueAndOperator($value, $operator, $useDefault = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->prepareValueAndOperator($value, $operator, $useDefault); + } + + /** + * Add a "where" clause comparing two columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string|array $first + * @param string|null $operator + * @param string|null $second + * @param string|null $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereColumn($first, $operator = null, $second = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereColumn($first, $operator, $second, $boolean); + } + + /** + * Add an "or where" clause comparing two columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string|array $first + * @param string|null $operator + * @param string|null $second + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereColumn($first, $operator = null, $second = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereColumn($first, $operator, $second); + } + + /** + * Add a raw where clause to the query. + * + * @param string $sql + * @param mixed $bindings + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereRaw($sql, $bindings = [], $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereRaw($sql, $bindings, $boolean); + } + + /** + * Add a raw or where clause to the query. + * + * @param string $sql + * @param mixed $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereRaw($sql, $bindings); + } + + /** + * Add a "where like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereLike($column, $value, $caseSensitive = false, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereLike($column, $value, $caseSensitive, $boolean, $not); + } + + /** + * Add an "or where like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereLike($column, $value, $caseSensitive = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereLike($column, $value, $caseSensitive); + } + + /** + * Add a "where not like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotLike($column, $value, $caseSensitive = false, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotLike($column, $value, $caseSensitive, $boolean); + } + + /** + * Add an "or where not like" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $value + * @param bool $caseSensitive + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotLike($column, $value, $caseSensitive = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotLike($column, $value, $caseSensitive); + } + + /** + * Add a "where in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereIn($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereIn($column, $values, $boolean, $not); + } + + /** + * Add an "or where in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereIn($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereIn($column, $values); + } + + /** + * Add a "where not in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotIn($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotIn($column, $values, $boolean); + } + + /** + * Add an "or where not in" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param mixed $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotIn($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotIn($column, $values); + } + + /** + * Add a "where in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereIntegerInRaw($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereIntegerInRaw($column, $values, $boolean, $not); + } + + /** + * Add an "or where in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereIntegerInRaw($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereIntegerInRaw($column, $values); + } + + /** + * Add a "where not in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereIntegerNotInRaw($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereIntegerNotInRaw($column, $values, $boolean); + } + + /** + * Add an "or where not in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereIntegerNotInRaw($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereIntegerNotInRaw($column, $values); + } + + /** + * Add a "where null" clause to the query. + * + * @param string|array|\Illuminate\Contracts\Database\Query\Expression $columns + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNull($columns, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNull($columns, $boolean, $not); + } + + /** + * Add an "or where null" clause to the query. + * + * @param string|array|\Illuminate\Contracts\Database\Query\Expression $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNull($column); + } + + /** + * Add a "where not null" clause to the query. + * + * @param string|array|\Illuminate\Contracts\Database\Query\Expression $columns + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotNull($columns, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotNull($columns, $boolean); + } + + /** + * Add a where between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereBetween($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereBetween($column, $values, $boolean, $not); + } + + /** + * Add a where between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereBetweenColumns($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereBetweenColumns($column, $values, $boolean, $not); + } + + /** + * Add an or where between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereBetween($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereBetween($column, $values); + } + + /** + * Add an or where between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereBetweenColumns($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereBetweenColumns($column, $values); + } + + /** + * Add a where not between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotBetween($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotBetween($column, $values, $boolean); + } + + /** + * Add a where not between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotBetweenColumns($column, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotBetweenColumns($column, $values, $boolean); + } + + /** + * Add an or where not between statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotBetween($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotBetween($column, $values); + } + + /** + * Add an or where not between statement using columns to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotBetweenColumns($column, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotBetweenColumns($column, $values); + } + + /** + * Add an "or where not null" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotNull($column); + } + + /** + * Add a "where date" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDate($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereDate($column, $operator, $value, $boolean); + } + + /** + * Add an "or where date" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDate($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereDate($column, $operator, $value); + } + + /** + * Add a "where time" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereTime($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereTime($column, $operator, $value, $boolean); + } + + /** + * Add an "or where time" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|null $operator + * @param \DateTimeInterface|string|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereTime($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereTime($column, $operator, $value); + } + + /** + * Add a "where day" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereDay($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereDay($column, $operator, $value, $boolean); + } + + /** + * Add an "or where day" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereDay($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereDay($column, $operator, $value); + } + + /** + * Add a "where month" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereMonth($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereMonth($column, $operator, $value, $boolean); + } + + /** + * Add an "or where month" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereMonth($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereMonth($column, $operator, $value); + } + + /** + * Add a "where year" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereYear($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereYear($column, $operator, $value, $boolean); + } + + /** + * Add an "or where year" statement to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @param \DateTimeInterface|string|int|null $operator + * @param \DateTimeInterface|string|int|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereYear($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereYear($column, $operator, $value); + } + + /** + * Add a nested where statement to the query. + * + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNested($callback, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNested($callback, $boolean); + } + + /** + * Create a new query instance for nested where condition. + * + * @return \Illuminate\Database\Query\Builder + * @static + */ + public static function forNestedWhere() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forNestedWhere(); + } + + /** + * Add another query builder as a nested where to the query builder. + * + * @param \Illuminate\Database\Query\Builder $query + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addNestedWhereQuery($query, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addNestedWhereQuery($query, $boolean); + } + + /** + * Add an exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereExists($callback, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereExists($callback, $boolean, $not); + } + + /** + * Add an or exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereExists($callback, $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereExists($callback, $not); + } + + /** + * Add a where not exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNotExists($callback, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNotExists($callback, $boolean); + } + + /** + * Add a where not exists clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $callback + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNotExists($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNotExists($callback); + } + + /** + * Add an exists clause to the query. + * + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addWhereExistsQuery($query, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addWhereExistsQuery($query, $boolean, $not); + } + + /** + * Adds a where condition using row values. + * + * @param array $columns + * @param string $operator + * @param array $values + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function whereRowValues($columns, $operator, $values, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereRowValues($columns, $operator, $values, $boolean); + } + + /** + * Adds an or where condition using row values. + * + * @param array $columns + * @param string $operator + * @param array $values + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereRowValues($columns, $operator, $values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereRowValues($columns, $operator, $values); + } + + /** + * Add a "where JSON contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonContains($column, $value, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonContains($column, $value, $boolean, $not); + } + + /** + * Add an "or where JSON contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonContains($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonContains($column, $value); + } + + /** + * Add a "where JSON not contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonDoesntContain($column, $value, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonDoesntContain($column, $value, $boolean); + } + + /** + * Add an "or where JSON not contains" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonDoesntContain($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonDoesntContain($column, $value); + } + + /** + * Add a "where JSON overlaps" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonOverlaps($column, $value, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonOverlaps($column, $value, $boolean, $not); + } + + /** + * Add an "or where JSON overlaps" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonOverlaps($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonOverlaps($column, $value); + } + + /** + * Add a "where JSON not overlap" clause to the query. + * + * @param string $column + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonDoesntOverlap($column, $value, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonDoesntOverlap($column, $value, $boolean); + } + + /** + * Add an "or where JSON not overlap" clause to the query. + * + * @param string $column + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonDoesntOverlap($column, $value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonDoesntOverlap($column, $value); + } + + /** + * Add a clause that determines if a JSON path exists to the query. + * + * @param string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonContainsKey($column, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonContainsKey($column, $boolean, $not); + } + + /** + * Add an "or" clause that determines if a JSON path exists to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonContainsKey($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonContainsKey($column); + } + + /** + * Add a clause that determines if a JSON path does not exist to the query. + * + * @param string $column + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonDoesntContainKey($column, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonDoesntContainKey($column, $boolean); + } + + /** + * Add an "or" clause that determines if a JSON path does not exist to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonDoesntContainKey($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonDoesntContainKey($column); + } + + /** + * Add a "where JSON length" clause to the query. + * + * @param string $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereJsonLength($column, $operator, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereJsonLength($column, $operator, $value, $boolean); + } + + /** + * Add an "or where JSON length" clause to the query. + * + * @param string $column + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereJsonLength($column, $operator, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereJsonLength($column, $operator, $value); + } + + /** + * Handles dynamic "where" clauses to the query. + * + * @param string $method + * @param array $parameters + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function dynamicWhere($method, $parameters) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dynamicWhere($method, $parameters); + } + + /** + * Add a "where fulltext" clause to the query. + * + * @param string|string[] $columns + * @param string $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereFullText($columns, $value, $options = [], $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereFullText($columns, $value, $options, $boolean); + } + + /** + * Add a "or where fulltext" clause to the query. + * + * @param string|string[] $columns + * @param string $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereFullText($columns, $value, $options = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereFullText($columns, $value, $options); + } + + /** + * Add a "where" clause to the query for multiple columns with "and" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereAll($columns, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereAll($columns, $operator, $value, $boolean); + } + + /** + * Add an "or where" clause to the query for multiple columns with "and" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereAll($columns, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereAll($columns, $operator, $value); + } + + /** + * Add a "where" clause to the query for multiple columns with "or" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereAny($columns, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereAny($columns, $operator, $value, $boolean); + } + + /** + * Add an "or where" clause to the query for multiple columns with "or" conditions between them. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereAny($columns, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereAny($columns, $operator, $value); + } + + /** + * Add a "where not" clause to the query for multiple columns where none of the conditions should be true. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNone($columns, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNone($columns, $operator, $value, $boolean); + } + + /** + * Add an "or where not" clause to the query for multiple columns where none of the conditions should be true. + * + * @param \Illuminate\Contracts\Database\Query\Expression[]|\Closure[]|string[] $columns + * @param mixed $operator + * @param mixed $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNone($columns, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNone($columns, $operator, $value); + } + + /** + * Add a "group by" clause to the query. + * + * @param array|\Illuminate\Contracts\Database\Query\Expression|string $groups + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function groupBy(...$groups) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->groupBy(...$groups); + } + + /** + * Add a raw groupBy clause to the query. + * + * @param string $sql + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function groupByRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->groupByRaw($sql, $bindings); + } + + /** + * Add a "having" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column + * @param \DateTimeInterface|string|int|float|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|\DateTimeInterface|string|int|float|null $value + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function having($column, $operator = null, $value = null, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->having($column, $operator, $value, $boolean); + } + + /** + * Add an "or having" clause to the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|\Closure|string $column + * @param \DateTimeInterface|string|int|float|null $operator + * @param \Illuminate\Contracts\Database\Query\Expression|\DateTimeInterface|string|int|float|null $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHaving($column, $operator = null, $value = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHaving($column, $operator, $value); + } + + /** + * Add a nested having statement to the query. + * + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingNested($callback, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingNested($callback, $boolean); + } + + /** + * Add another query builder as a nested having to the query builder. + * + * @param \Illuminate\Database\Query\Builder $query + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function addNestedHavingQuery($query, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addNestedHavingQuery($query, $boolean); + } + + /** + * Add a "having null" clause to the query. + * + * @param array|string $columns + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingNull($columns, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingNull($columns, $boolean, $not); + } + + /** + * Add an "or having null" clause to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHavingNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHavingNull($column); + } + + /** + * Add a "having not null" clause to the query. + * + * @param array|string $columns + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingNotNull($columns, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingNotNull($columns, $boolean); + } + + /** + * Add an "or having not null" clause to the query. + * + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHavingNotNull($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHavingNotNull($column); + } + + /** + * Add a "having between " clause to the query. + * + * @param string $column + * @param string $boolean + * @param bool $not + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingBetween($column, $values, $boolean = 'and', $not = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingBetween($column, $values, $boolean, $not); + } + + /** + * Add a raw having clause to the query. + * + * @param string $sql + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function havingRaw($sql, $bindings = [], $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->havingRaw($sql, $bindings, $boolean); + } + + /** + * Add a raw or having clause to the query. + * + * @param string $sql + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orHavingRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orHavingRaw($sql, $bindings); + } + + /** + * Add an "order by" clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Contracts\Database\Query\Expression|string $column + * @param string $direction + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function orderBy($column, $direction = 'asc') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orderBy($column, $direction); + } + + /** + * Add a descending "order by" clause to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|\Illuminate\Contracts\Database\Query\Expression|string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orderByDesc($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orderByDesc($column); + } + + /** + * Put the query's results in random order. + * + * @param string|int $seed + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function inRandomOrder($seed = '') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->inRandomOrder($seed); + } + + /** + * Add a raw "order by" clause to the query. + * + * @param string $sql + * @param array $bindings + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orderByRaw($sql, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orderByRaw($sql, $bindings); + } + + /** + * Alias to set the "offset" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function skip($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->skip($value); + } + + /** + * Set the "offset" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function offset($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->offset($value); + } + + /** + * Alias to set the "limit" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function take($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->take($value); + } + + /** + * Set the "limit" value of the query. + * + * @param int $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function limit($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->limit($value); + } + + /** + * Add a "group limit" clause to the query. + * + * @param int $value + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function groupLimit($value, $column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->groupLimit($value, $column); + } + + /** + * Set the limit and offset for a given page. + * + * @param int $page + * @param int $perPage + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forPage($page, $perPage = 15) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forPage($page, $perPage); + } + + /** + * Constrain the query to the previous "page" of results before a given ID. + * + * @param int $perPage + * @param int|null $lastId + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forPageBeforeId($perPage, $lastId, $column); + } + + /** + * Constrain the query to the next "page" of results after a given ID. + * + * @param int $perPage + * @param int|null $lastId + * @param string $column + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->forPageAfterId($perPage, $lastId, $column); + } + + /** + * Remove all existing orders and optionally add a new order. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Contracts\Database\Query\Expression|string|null $column + * @param string $direction + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function reorder($column = null, $direction = 'asc') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->reorder($column, $direction); + } + + /** + * Add a union statement to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $query + * @param bool $all + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function union($query, $all = false) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->union($query, $all); + } + + /** + * Add a union all statement to the query. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*> $query + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function unionAll($query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->unionAll($query); + } + + /** + * Lock the selected rows in the table. + * + * @param string|bool $value + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function lock($value = true) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->lock($value); + } + + /** + * Lock the selected rows in the table for updating. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function lockForUpdate() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->lockForUpdate(); + } + + /** + * Share lock the selected rows in the table. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function sharedLock() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->sharedLock(); + } + + /** + * Register a closure to be invoked before the query is executed. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function beforeQuery($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->beforeQuery($callback); + } + + /** + * Invoke the "before query" modification callbacks. + * + * @return void + * @static + */ + public static function applyBeforeQueryCallbacks() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + $instance->applyBeforeQueryCallbacks(); + } + + /** + * Get the SQL representation of the query. + * + * @return string + * @static + */ + public static function toSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->toSql(); + } + + /** + * Get the raw SQL representation of the query with embedded bindings. + * + * @return string + * @static + */ + public static function toRawSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->toRawSql(); + } + + /** + * Get a single expression value from the first result of a query. + * + * @return mixed + * @static + */ + public static function rawValue($expression, $bindings = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->rawValue($expression, $bindings); + } + + /** + * Get the count of the total records for the paginator. + * + * @param array $columns + * @return int + * @static + */ + public static function getCountForPagination($columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getCountForPagination($columns); + } + + /** + * Concatenate values of a given column as a string. + * + * @param string $column + * @param string $glue + * @return string + * @static + */ + public static function implode($column, $glue = '') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->implode($column, $glue); + } + + /** + * Determine if any rows exist for the current query. + * + * @return bool + * @static + */ + public static function exists() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->exists(); + } + + /** + * Determine if no rows exist for the current query. + * + * @return bool + * @static + */ + public static function doesntExist() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->doesntExist(); + } + + /** + * Execute the given callback if no rows exist for the current query. + * + * @return mixed + * @static + */ + public static function existsOr($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->existsOr($callback); + } + + /** + * Execute the given callback if rows exist for the current query. + * + * @return mixed + * @static + */ + public static function doesntExistOr($callback) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->doesntExistOr($callback); + } + + /** + * Retrieve the "count" result of the query. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $columns + * @return int + * @static + */ + public static function count($columns = '*') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->count($columns); + } + + /** + * Retrieve the minimum value of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function min($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->min($column); + } + + /** + * Retrieve the maximum value of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function max($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->max($column); + } + + /** + * Retrieve the sum of the values of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function sum($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->sum($column); + } + + /** + * Retrieve the average of the values of a given column. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function avg($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->avg($column); + } + + /** + * Alias for the "avg" method. + * + * @param \Illuminate\Contracts\Database\Query\Expression|string $column + * @return mixed + * @static + */ + public static function average($column) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->average($column); + } + + /** + * Execute an aggregate function on the database. + * + * @param string $function + * @param array $columns + * @return mixed + * @static + */ + public static function aggregate($function, $columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->aggregate($function, $columns); + } + + /** + * Execute a numeric aggregate function on the database. + * + * @param string $function + * @param array $columns + * @return float|int + * @static + */ + public static function numericAggregate($function, $columns = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->numericAggregate($function, $columns); + } + + /** + * Insert new records into the database. + * + * @return bool + * @static + */ + public static function insert($values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insert($values); + } + + /** + * Insert new records into the database while ignoring errors. + * + * @return int + * @static + */ + public static function insertOrIgnore($values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertOrIgnore($values); + } + + /** + * Insert a new record and get the value of the primary key. + * + * @param string|null $sequence + * @return int + * @static + */ + public static function insertGetId($values, $sequence = null) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertGetId($values, $sequence); + } + + /** + * Insert new records into the table using a subquery. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return int + * @static + */ + public static function insertUsing($columns, $query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertUsing($columns, $query); + } + + /** + * Insert new records into the table using a subquery while ignoring errors. + * + * @param \Closure|\Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<*>|string $query + * @return int + * @static + */ + public static function insertOrIgnoreUsing($columns, $query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->insertOrIgnoreUsing($columns, $query); + } + + /** + * Update records in a PostgreSQL database using the update from syntax. + * + * @return int + * @static + */ + public static function updateFrom($values) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->updateFrom($values); + } + + /** + * Insert or update a record matching the attributes, and fill it with values. + * + * @return bool + * @static + */ + public static function updateOrInsert($attributes, $values = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->updateOrInsert($attributes, $values); + } + + /** + * Increment the given column's values by the given amounts. + * + * @param array $columns + * @param array $extra + * @return int + * @throws \InvalidArgumentException + * @static + */ + public static function incrementEach($columns, $extra = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->incrementEach($columns, $extra); + } + + /** + * Decrement the given column's values by the given amounts. + * + * @param array $columns + * @param array $extra + * @return int + * @throws \InvalidArgumentException + * @static + */ + public static function decrementEach($columns, $extra = []) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->decrementEach($columns, $extra); + } + + /** + * Run a truncate statement on the table. + * + * @return void + * @static + */ + public static function truncate() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + $instance->truncate(); + } + + /** + * Get all of the query builder's columns in a text-only array with all expressions evaluated. + * + * @return array + * @static + */ + public static function getColumns() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getColumns(); + } + + /** + * Create a raw database expression. + * + * @param mixed $value + * @return \Illuminate\Contracts\Database\Query\Expression + * @static + */ + public static function raw($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->raw($value); + } + + /** + * Get the current query value bindings in a flattened array. + * + * @return array + * @static + */ + public static function getBindings() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getBindings(); + } + + /** + * Get the raw array of bindings. + * + * @return array + * @static + */ + public static function getRawBindings() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getRawBindings(); + } + + /** + * Set the bindings on the query builder. + * + * @param string $type + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function setBindings($bindings, $type = 'where') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->setBindings($bindings, $type); + } + + /** + * Add a binding to the query. + * + * @param mixed $value + * @param string $type + * @return \Illuminate\Database\Eloquent\Builder + * @throws \InvalidArgumentException + * @static + */ + public static function addBinding($value, $type = 'where') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->addBinding($value, $type); + } + + /** + * Cast the given binding value. + * + * @param mixed $value + * @return mixed + * @static + */ + public static function castBinding($value) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->castBinding($value); + } + + /** + * Merge an array of bindings into our bindings. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function mergeBindings($query) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->mergeBindings($query); + } + + /** + * Remove all of the expressions from a list of bindings. + * + * @return array + * @static + */ + public static function cleanBindings($bindings) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->cleanBindings($bindings); + } + + /** + * Get the database query processor instance. + * + * @return \Illuminate\Database\Query\Processors\Processor + * @static + */ + public static function getProcessor() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getProcessor(); + } + + /** + * Get the query grammar instance. + * + * @return \Illuminate\Database\Query\Grammars\Grammar + * @static + */ + public static function getGrammar() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->getGrammar(); + } + + /** + * Use the "write" PDO connection when executing the query. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function useWritePdo() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->useWritePdo(); + } + + /** + * Clone the query without the given properties. + * + * @return static + * @static + */ + public static function cloneWithout($properties) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->cloneWithout($properties); + } + + /** + * Clone the query without the given bindings. + * + * @return static + * @static + */ + public static function cloneWithoutBindings($except) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->cloneWithoutBindings($except); + } + + /** + * Dump the current SQL and bindings. + * + * @param mixed $args + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function dump(...$args) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dump(...$args); + } + + /** + * Dump the raw current SQL with embedded bindings. + * + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function dumpRawSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dumpRawSql(); + } + + /** + * Die and dump the current SQL and bindings. + * + * @return never + * @static + */ + public static function dd() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->dd(); + } + + /** + * Die and dump the current SQL with embedded bindings. + * + * @return never + * @static + */ + public static function ddRawSql() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->ddRawSql(); + } + + /** + * Add a where clause to determine if a "date" column is in the past to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function wherePast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->wherePast($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the past or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNowOrPast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNowOrPast($columns); + } + + /** + * Add an "or where" clause to determine if a "date" column is in the past to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWherePast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWherePast($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the past or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNowOrPast($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNowOrPast($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the future to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereFuture($columns); + } + + /** + * Add a where clause to determine if a "date" column is in the future or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereNowOrFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereNowOrFuture($columns); + } + + /** + * Add an "or where" clause to determine if a "date" column is in the future to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereFuture($columns); + } + + /** + * Add an "or where" clause to determine if a "date" column is in the future or now to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereNowOrFuture($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereNowOrFuture($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is today to the query. + * + * @param array|string $columns + * @param string $boolean + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereToday($columns, $boolean = 'and') + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereToday($columns, $boolean); + } + + /** + * Add a "where date" clause to determine if a "date" column is before today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereBeforeToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereBeforeToday($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is today or before to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereTodayOrBefore($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereTodayOrBefore($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is after today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereAfterToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereAfterToday($columns); + } + + /** + * Add a "where date" clause to determine if a "date" column is today or after to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function whereTodayOrAfter($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->whereTodayOrAfter($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is today to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereToday($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is before today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereBeforeToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereBeforeToday($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is today or before to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereTodayOrBefore($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereTodayOrBefore($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is after today. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereAfterToday($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereAfterToday($columns); + } + + /** + * Add an "or where date" clause to determine if a "date" column is today or after to the query. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Builder + * @static + */ + public static function orWhereTodayOrAfter($columns) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->orWhereTodayOrAfter($columns); + } + + /** + * Explains the query. + * + * @return \Illuminate\Support\Collection + * @static + */ + public static function explain() + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->explain(); + } + + /** + * Register a custom macro. + * + * @param string $name + * @param object|callable $macro + * @param-closure-this static $macro + * @return void + * @static + */ + public static function macro($name, $macro) + { + \Illuminate\Database\Query\Builder::macro($name, $macro); + } + + /** + * Mix another object into the class. + * + * @param object $mixin + * @param bool $replace + * @return void + * @throws \ReflectionException + * @static + */ + public static function mixin($mixin, $replace = true) + { + \Illuminate\Database\Query\Builder::mixin($mixin, $replace); + } + + /** + * Flush the existing macros. + * + * @return void + * @static + */ + public static function flushMacros() + { + \Illuminate\Database\Query\Builder::flushMacros(); + } + + /** + * Dynamically handle calls to the class. + * + * @param string $method + * @param array $parameters + * @return mixed + * @throws \BadMethodCallException + * @static + */ + public static function macroCall($method, $parameters) + { + /** @var \Illuminate\Database\Query\Builder $instance */ + return $instance->macroCall($method, $parameters); + } + +} + class Event extends \Illuminate\Support\Facades\Event {} + class File extends \Illuminate\Support\Facades\File {} + class Gate extends \Illuminate\Support\Facades\Gate {} + class Hash extends \Illuminate\Support\Facades\Hash {} + class Http extends \Illuminate\Support\Facades\Http {} + class Js extends \Illuminate\Support\Js {} + class Lang extends \Illuminate\Support\Facades\Lang {} + class Log extends \Illuminate\Support\Facades\Log {} + class Mail extends \Illuminate\Support\Facades\Mail {} + class Notification extends \Illuminate\Support\Facades\Notification {} + class Number extends \Illuminate\Support\Number {} + class Password extends \Illuminate\Support\Facades\Password {} + class Process extends \Illuminate\Support\Facades\Process {} + class Queue extends \Illuminate\Support\Facades\Queue {} + class RateLimiter extends \Illuminate\Support\Facades\RateLimiter {} + class Redirect extends \Illuminate\Support\Facades\Redirect {} + class Request extends \Illuminate\Support\Facades\Request {} + class Response extends \Illuminate\Support\Facades\Response {} + class Route extends \Illuminate\Support\Facades\Route {} + class Schedule extends \Illuminate\Support\Facades\Schedule {} + class Schema extends \Illuminate\Support\Facades\Schema {} + class Session extends \Illuminate\Support\Facades\Session {} + class Storage extends \Illuminate\Support\Facades\Storage {} + class Str extends \Illuminate\Support\Str {} + class URL extends \Illuminate\Support\Facades\URL {} + class Uri extends \Illuminate\Support\Uri {} + class Validator extends \Illuminate\Support\Facades\Validator {} + class View extends \Illuminate\Support\Facades\View {} + class Vite extends \Illuminate\Support\Facades\Vite {} +} + + + + + diff --git a/TA_website/_ide_helper_models.php b/TA_website/_ide_helper_models.php new file mode 100644 index 0000000..4ea9099 --- /dev/null +++ b/TA_website/_ide_helper_models.php @@ -0,0 +1,236 @@ + + */ + + +namespace App\Models{ +/** + * + * + * @property int $id + * @property string|null $transaction_code + * @property int $customer_id + * @property int $tailor_id + * @property \Illuminate\Support\Carbon $appointment_date + * @property string $appointment_time + * @property string $service_type + * @property string $category + * @property string|null $design_photo + * @property string|null $notes + * @property string $status + * @property numeric|null $total_price + * @property string $payment_status + * @property string|null $completion_date + * @property string|null $measurements + * @property string|null $repair_details + * @property string|null $repair_photo + * @property string|null $repair_notes + * @property string|null $completion_photo + * @property string|null $completion_notes + * @property string|null $accepted_at + * @property string|null $rejected_at + * @property string|null $completed_at + * @property string|null $pickup_date + * @property string|null $rejection_reason + * @property string|null $payment_method + * @property string|null $midtrans_snap_token + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\User $customer + * @property-read \App\Models\Measurement|null $measurement + * @property-read \App\Models\User $tailor + * @method static \Illuminate\Database\Eloquent\Builder|Booking newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Booking newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Booking query() + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereAcceptedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereAppointmentDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereAppointmentTime($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCategory($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletionDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletionNotes($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCompletionPhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereCustomerId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereDesignPhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereMeasurements($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereMidtransSnapToken($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereNotes($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking wherePaymentMethod($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking wherePaymentStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking wherePickupDate($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRejectedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRejectionReason($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRepairDetails($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRepairNotes($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereRepairPhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereServiceType($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereTailorId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereTotalPrice($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereTransactionCode($value) + * @method static \Illuminate\Database\Eloquent\Builder|Booking whereUpdatedAt($value) + */ + class Booking extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property-read \App\Models\User|null $customer + * @method static \Illuminate\Database\Eloquent\Builder|Measurement newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Measurement newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Measurement query() + */ + class Measurement extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property-read \App\Models\User|null $customer + * @property-read \Illuminate\Database\Eloquent\Collection $products + * @property-read int|null $products_count + * @method static \Illuminate\Database\Eloquent\Builder|Order newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Order newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Order query() + */ + class Order extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property-read \Illuminate\Database\Eloquent\Collection $orders + * @property-read int|null $orders_count + * @method static \Illuminate\Database\Eloquent\Builder|Product newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Product newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|Product query() + */ + class Product extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $user_id + * @property string $photo + * @property string|null $title + * @property string|null $description + * @property string|null $category + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\User $tailor + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery query() + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereCategory($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery wherePhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereTitle($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereUpdatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorGallery whereUserId($value) + */ + class TailorGallery extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property int $booking_id + * @property int $customer_id + * @property int $tailor_id + * @property numeric $rating + * @property string|null $review + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \App\Models\Booking $booking + * @property-read \App\Models\User $customer + * @property-read \App\Models\User $tailor + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating query() + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereBookingId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereCustomerId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereRating($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereReview($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereTailorId($value) + * @method static \Illuminate\Database\Eloquent\Builder|TailorRating whereUpdatedAt($value) + */ + class TailorRating extends \Eloquent {} +} + +namespace App\Models{ +/** + * + * + * @property int $id + * @property string $name + * @property string $email + * @property string $password + * @property string $role + * @property string|null $phone_number + * @property string|null $address + * @property numeric|null $latitude + * @property numeric|null $longitude + * @property string|null $shop_description + * @property string|null $profile_photo + * @property \Illuminate\Support\Carbon|null $email_verified_at + * @property string|null $remember_token + * @property \Illuminate\Support\Carbon|null $created_at + * @property \Illuminate\Support\Carbon|null $updated_at + * @property-read \Illuminate\Database\Eloquent\Collection $bookings + * @property-read int|null $bookings_count + * @property-read \Illuminate\Database\Eloquent\Collection $galleries + * @property-read int|null $galleries_count + * @property-read \Illuminate\Notifications\DatabaseNotificationCollection $notifications + * @property-read int|null $notifications_count + * @property-read \Illuminate\Database\Eloquent\Collection $orders + * @property-read int|null $orders_count + * @property-read \Illuminate\Database\Eloquent\Collection $reviews + * @property-read int|null $reviews_count + * @property-read \Illuminate\Database\Eloquent\Collection $tokens + * @property-read int|null $tokens_count + * @method static \Database\Factories\UserFactory factory($count = null, $state = []) + * @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery() + * @method static \Illuminate\Database\Eloquent\Builder|User newQuery() + * @method static \Illuminate\Database\Eloquent\Builder|User query() + * @method static \Illuminate\Database\Eloquent\Builder|User whereAddress($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereEmail($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereEmailVerifiedAt($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereLatitude($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereLongitude($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereName($value) + * @method static \Illuminate\Database\Eloquent\Builder|User wherePassword($value) + * @method static \Illuminate\Database\Eloquent\Builder|User wherePhoneNumber($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereProfilePhoto($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereRememberToken($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereRole($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereShopDescription($value) + * @method static \Illuminate\Database\Eloquent\Builder|User whereUpdatedAt($value) + */ + class User extends \Eloquent {} +} + diff --git a/TA_website/app/Http/Controllers/Admin/AuthController.php b/TA_website/app/Http/Controllers/Admin/AuthController.php new file mode 100644 index 0000000..44e66fd --- /dev/null +++ b/TA_website/app/Http/Controllers/Admin/AuthController.php @@ -0,0 +1,143 @@ +apiService = $apiService; + } + + public function showLoginForm() + { + return view('admin.auth.login'); + } + + public function login(Request $request) + { + $credentials = $request->validate([ + 'email' => ['required', 'email'], + 'password' => ['required'], + ]); + + try { + // Login ke API terlebih dahulu + // Format URL yang benar adalah https://api.tailors.stuffly.my.id/api/admin/login + $response = $this->apiService->post('admin/login', [ + 'email' => $credentials['email'], + 'password' => $credentials['password'], + ]); + + \Log::info('API Login Response', [ + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->successful()) { + $data = $response->json(); + + if ($data['success'] && isset($data['data']['access_token'])) { + // Simpan token dan token type di session + session([ + 'api_token' => $data['data']['access_token'], + 'token_type' => $data['data']['token_type'], + 'user_data' => $data['data']['user'] + ]); + + // Coba cari user di database, atau login dengan user yang sudah ada + // tanpa membuat user baru (karena kolom sudah ditambahkan di migrasi) + $user = User::where('email', $credentials['email'])->first(); + + if ($user) { + // Update data user jika ada + $apiUser = $data['data']['user']; + $user->update([ + 'name' => $apiUser['name'], + 'role' => $apiUser['role'] ?? null, + 'phone_number' => $apiUser['phone_number'] ?? null, + 'address' => $apiUser['address'] ?? null, + ]); + } else { + // Buat user baru jika belum ada + $apiUser = $data['data']['user']; + $user = User::create([ + 'name' => $apiUser['name'], + 'email' => $apiUser['email'], + 'password' => Hash::make($credentials['password']), + 'role' => $apiUser['role'] ?? null, + 'phone_number' => $apiUser['phone_number'] ?? null, + 'address' => $apiUser['address'] ?? null, + ]); + } + + // Login ke aplikasi web dengan user yang ada + Auth::login($user); + $request->session()->regenerate(); + + // Redirect ke dashboard + return redirect()->intended(route('admin.dashboard')); + } + } + + // Jika gagal, tampilkan pesan error dari API + $errorMessage = 'Email atau password salah.'; + if ($response->json() && isset($response->json()['message'])) { + $errorMessage = $response->json()['message']; + } + + return back()->withErrors([ + 'email' => $errorMessage, + ])->onlyInput('email'); + + } catch (\Exception $e) { + \Log::error('Login Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->withErrors([ + 'email' => 'Terjadi kesalahan saat menghubungi server. Silakan coba lagi: ' . $e->getMessage(), + ])->onlyInput('email'); + } + } + + public function logout(Request $request) + { + try { + // Logout dari API + $this->apiService->post('admin/logout'); + } catch (\Exception $e) { + \Log::error('API Logout Error:', ['message' => $e->getMessage()]); + } + + // Hapus token dari session + session()->forget(['api_token', 'token_type', 'user_data']); + + // Logout dari aplikasi web + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return redirect()->route('admin.login'); + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Controllers/Admin/BankAccountController.php b/TA_website/app/Http/Controllers/Admin/BankAccountController.php new file mode 100644 index 0000000..046f5f0 --- /dev/null +++ b/TA_website/app/Http/Controllers/Admin/BankAccountController.php @@ -0,0 +1,291 @@ +apiService = $apiService; + } + + /** + * Display a listing of pending bank accounts. + * + * @return \Illuminate\Http\Response + */ + public function pending() + { + try { + // Gunakan endpoint yang benar sesuai dengan API + $response = $this->apiService->get('admin/bank-accounts/pending'); + + // Log API response untuk debugging + \Log::debug('Bank Account Pending API Response:', [ + 'url' => 'admin/bank-accounts/pending', + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->successful()) { + $bankAccounts = $response->json()['data'] ?? []; + return view('admin.bank-accounts.pending', compact('bankAccounts')); + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error lain + return back()->with('error', 'Gagal memuat data akun bank: ' . ($response->json()['message'] ?? 'Unknown error')); + + } catch (\Exception $e) { + \Log::error('Bank Account Pending Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->with('error', 'Terjadi kesalahan saat memuat data akun bank'); + } + } + + /** + * Display a listing of verified bank accounts. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function verified(Request $request) + { + try { + // Buat query parameters dari request + $params = []; + if ($request->has('status')) { + $params['status'] = $request->status; + } + if ($request->has('search')) { + $params['search'] = $request->search; + } + + // Gunakan endpoint untuk mendapatkan akun bank yang sudah diverifikasi + $response = $this->apiService->get('admin/bank-accounts/verified', $params); + + // Log API response untuk debugging + \Log::debug('Bank Account Verified API Response:', [ + 'url' => 'admin/bank-accounts/verified', + 'params' => $params, + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->successful()) { + $bankAccounts = $response->json()['data'] ?? []; + return view('admin.bank-accounts.verified', compact('bankAccounts')); + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error lain + return back()->with('error', 'Gagal memuat data akun bank: ' . ($response->json()['message'] ?? 'Unknown error')); + + } catch (\Exception $e) { + \Log::error('Bank Account Verified Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->with('error', 'Terjadi kesalahan saat memuat data akun bank'); + } + } + + /** + * Display details of specific bank account with withdrawal history. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function detail($id) + { + try { + // Gunakan endpoint untuk mendapatkan detail akun bank + $response = $this->apiService->get("admin/bank-accounts/{$id}"); + + // Log API response untuk debugging + \Log::debug('Bank Account Detail API Response:', [ + 'url' => "admin/bank-accounts/{$id}", + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->successful()) { + $bankAccount = $response->json()['data'] ?? null; + + if ($bankAccount) { + return view('admin.bank-accounts.detail', compact('bankAccount')); + } + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error lain + return back()->with('error', 'Akun bank tidak ditemukan: ' . ($response->json()['message'] ?? 'Unknown error')); + + } catch (\Exception $e) { + \Log::error('Bank Account Detail Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->with('error', 'Terjadi kesalahan saat memuat data akun bank'); + } + } + + /** + * Show the form for verifying a bank account. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function showVerify($id) + { + try { + // Gunakan data yang sudah ada dari daftar bank-accounts/pending + // Karena API route untuk mengambil detail bank account sepertinya tidak tersedia + $response = $this->apiService->get("admin/bank-accounts/pending"); + + // Log API response untuk debugging + \Log::debug('Bank Account Show Detail API Response:', [ + 'url' => "admin/bank-accounts/pending", + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->successful()) { + $bankAccounts = $response->json()['data'] ?? []; + + // Cari akun bank dengan ID yang sesuai + $bankAccount = null; + foreach ($bankAccounts as $account) { + if ($account['id'] == $id) { + $bankAccount = $account; + break; + } + } + + if ($bankAccount) { + return view('admin.bank-accounts.verify', compact('bankAccount')); + } + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error lain + return redirect()->route('admin.bank-accounts.pending') + ->with('error', 'Akun bank tidak ditemukan: ' . ($response->json()['message'] ?? 'Unknown error')); + + } catch (\Exception $e) { + \Log::error('Bank Account Show Verify Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return redirect()->route('admin.bank-accounts.pending') + ->with('error', 'Terjadi kesalahan saat memuat data akun bank'); + } + } + + /** + * Verify the specified bank account. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function verify(Request $request, $id) + { + try { + // Validasi request + $request->validate([ + 'status' => 'required|in:active,rejected', + 'rejection_reason' => 'required_if:status,rejected', + ]); + + $data = [ + 'status' => $request->status, + 'rejection_reason' => $request->rejection_reason, + ]; + + // Pastikan path API sudah benar - gunakan /admin bukan /api/admin + $response = $this->apiService->post("admin/bank-accounts/{$id}/verify", $data); + + // Log API response untuk debugging + \Log::debug('Bank Account Verify API Response:', [ + 'url' => "admin/bank-accounts/{$id}/verify", + 'data' => $data, + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->successful()) { + return redirect()->route('admin.bank-accounts.pending') + ->with('success', 'Akun bank berhasil diverifikasi'); + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error validasi + if ($response->status() === 422) { + return back()->withErrors($response->json()['data'] ?? []) + ->withInput(); + } + + // Jika terjadi error lain + return back()->with('error', 'Gagal memverifikasi akun bank: ' . ($response->json()['message'] ?? 'Unknown error')) + ->withInput(); + + } catch (\Exception $e) { + \Log::error('Bank Account Verify Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->with('error', 'Terjadi kesalahan saat memverifikasi akun bank') + ->withInput(); + } + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Controllers/Admin/BookingController.php b/TA_website/app/Http/Controllers/Admin/BookingController.php new file mode 100644 index 0000000..3c2f9bf --- /dev/null +++ b/TA_website/app/Http/Controllers/Admin/BookingController.php @@ -0,0 +1,14 @@ +latest()->paginate(10); + return view('admin.customers.index', compact('customers')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + return view('admin.customers.create'); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users', + 'password' => 'required|string|min:8', + 'phone' => 'required|string|max:15', + 'address' => 'required|string', + ]); + + User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + 'phone' => $request->phone, + 'address' => $request->address, + 'role' => 'pelanggan', + ]); + + return redirect()->route('admin.customers.index') + ->with('success', 'Pelanggan berhasil ditambahkan'); + } + + /** + * Display the specified resource. + */ + public function show(User $customer) + { + return view('admin.customers.show', compact('customer')); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(User $customer) + { + return view('admin.customers.edit', compact('customer')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, User $customer) + { + $request->validate([ + 'name' => 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users,email,' . $customer->id, + 'phone' => 'required|string|max:15', + 'address' => 'required|string', + ]); + + $data = [ + 'name' => $request->name, + 'email' => $request->email, + 'phone' => $request->phone, + 'address' => $request->address, + ]; + + // Jika password baru diisi + if ($request->filled('password')) { + $request->validate([ + 'password' => 'required|string|min:8', + ]); + $data['password'] = Hash::make($request->password); + } + + $customer->update($data); + + return redirect()->route('admin.customers.index') + ->with('success', 'Data pelanggan berhasil diperbarui'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(User $customer) + { + $customer->delete(); + + return redirect()->route('admin.customers.index') + ->with('success', 'Pelanggan berhasil dihapus'); + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Controllers/Admin/DashboardController.php b/TA_website/app/Http/Controllers/Admin/DashboardController.php new file mode 100644 index 0000000..03edae1 --- /dev/null +++ b/TA_website/app/Http/Controllers/Admin/DashboardController.php @@ -0,0 +1,101 @@ +apiService = $apiService; + } + + public function index() + { + // Periksa apakah token API tersedia di session + $token = session('api_token'); + $tokenType = session('token_type'); + $userData = session('user_data'); + + if (!$token || !$tokenType) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Tampilkan data dari API atau gunakan data yang sudah ada di session + try { + // Coba ambil data dari API untuk dashboard + // Jika tidak berhasil, gunakan data lokal saja + $response = $this->apiService->get('api/admin/dashboard'); + + if (!$response->successful()) { + // Token tidak valid atau kedaluwarsa + \Log::warning('Dashboard API Error: Token tidak valid', [ + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->status() === 401) { + session()->forget(['api_token', 'token_type', 'user_data']); + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + } else { + // Jika berhasil, gunakan data dari API + $apiData = $response->json(); + if (isset($apiData['data'])) { + // Simpan data dari API ke variabel untuk dikirim ke view + $dashboardData = $apiData['data']; + return view('admin.dashboard', compact('dashboardData', 'userData')); + } + } + } catch (\Exception $e) { + \Log::error('Dashboard API Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + } + + // Jika tidak berhasil mengambil data dari API, gunakan data lokal + // Menghitung total data untuk statistik + $totalCustomers = User::where('role', 'pelanggan')->count(); + $totalOrders = Booking::count() ?? 0; + + // Menghitung total pengukuran dari data JSON di tabel bookings + $totalMeasurements = Booking::whereNotNull('measurements')->count() ?? 0; + + // Mengambil pesanan terbaru + $recentOrders = Booking::with('customer') + ->latest() + ->take(5) + ->get(); + + return view('admin.dashboard', compact( + 'totalCustomers', + 'totalOrders', + 'totalMeasurements', + 'recentOrders', + 'userData' + )); + } +} diff --git a/TA_website/app/Http/Controllers/Admin/LoginController.php b/TA_website/app/Http/Controllers/Admin/LoginController.php new file mode 100644 index 0000000..d5f353e --- /dev/null +++ b/TA_website/app/Http/Controllers/Admin/LoginController.php @@ -0,0 +1,113 @@ +apiService = $apiService; + } + + public function showLoginForm() + { + return view('admin.auth.login'); + } + + public function login(Request $request) + { + $credentials = $request->validate([ + 'email' => 'required|email', + 'password' => 'required', + ]); + + try { + // Call API for authentication without using the default authorization + $response = $this->apiService->http()->post($this->apiService->url('api/admin/login'), [ + 'email' => $credentials['email'], + 'password' => $credentials['password'], + ]); + + $data = $response->json(); + + // Log the response for debugging + Log::info('API Login Response', [ + 'status' => $response->status(), + 'body' => $data + ]); + + if ($response->successful() && isset($data['success']) && $data['success']) { + // Store user information and tokens in session + $request->session()->put('api_token', $data['data']['access_token']); + $request->session()->put('token_type', $data['data']['token_type']); + $request->session()->put('user', $data['data']['user']); + + // Return JSON response if requested + if ($request->expectsJson()) { + return response()->json($data); + } + + // Redirect to dashboard + return redirect()->route('admin.dashboard'); + } + + // Return JSON error if requested + if ($request->expectsJson()) { + return response()->json([ + 'success' => false, + 'message' => $data['message'] ?? 'Authentication failed' + ], 401); + } + + // Default error message + return back()->withErrors([ + 'email' => $data['message'] ?? 'The provided credentials do not match our records.', + ]); + + } catch (\Exception $e) { + Log::error('Login Error', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + // Return JSON error if requested + if ($request->expectsJson()) { + return response()->json([ + 'success' => false, + 'message' => 'An error occurred during login. Please try again.' + ], 500); + } + + return back()->withErrors([ + 'email' => 'An error occurred during login. Please try again.' + ]); + } + } + + public function logout(Request $request) + { + $request->session()->forget(['api_token', 'token_type', 'user']); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return redirect()->route('admin.login'); + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Controllers/Admin/SpecializationController.php b/TA_website/app/Http/Controllers/Admin/SpecializationController.php new file mode 100644 index 0000000..2926df1 --- /dev/null +++ b/TA_website/app/Http/Controllers/Admin/SpecializationController.php @@ -0,0 +1,65 @@ +apiService = $apiService; + } + + public function index() + { + try { + $token = session('api_token'); + $tokenType = session('token_type'); + + if (!$token || !$tokenType) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Debug log untuk token + \Log::info('Token Info:', [ + 'token' => $token, + 'type' => $tokenType + ]); + + $response = $this->apiService->get('api/tailors/all'); + + \Log::info('Tailors API Response', [ + 'status' => $response->status(), + 'body' => $response->json() + ]); + + if ($response->successful()) { + $data = $response->json(); + if ($data['status'] === 'success' && isset($data['data'])) { + $tailors = $data['data']; + return view('admin.tailors.index', compact('tailors')); + } + } + + if ($response->status() === 401) { + // Debug log untuk unauthorized + \Log::warning('Unauthorized Access:', [ + 'headers' => $response->headers(), + 'body' => $response->json() + ]); + + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $errorMessage = $response->json()['message'] ?? 'Unknown error'; + \Log::error('Tailor Index Error:', [ + 'status' => $response->status(), + 'message' => $errorMessage, + 'headers' => $response->headers() + ]); + + return back()->with('error', 'Gagal memuat data penjahit: ' . $errorMessage); + } catch (\Exception $e) { + \Log::error('Tailor Index Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return back()->with('error', 'Terjadi kesalahan saat memuat data penjahit'); + } + } + + public function create() + { + return view('admin.tailors.create'); + } + + public function store(Request $request) + { + try { + $token = session('api_token'); + $tokenType = session('token_type'); + + if (!$token || !$tokenType) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $response = $this->apiService->post('api/users/tailors', $request->all()); + + if ($response->successful()) { + return redirect()->route('admin.tailors.index') + ->with('success', 'Penjahit berhasil ditambahkan'); + } + + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $errorMessage = $response->json()['message'] ?? 'Unknown error'; + \Log::error('Tailor Store Error:', [ + 'status' => $response->status(), + 'message' => $errorMessage, + 'request' => $request->all() + ]); + + return back()->with('error', 'Gagal menambahkan penjahit: ' . $errorMessage); + } catch (\Exception $e) { + \Log::error('Tailor Store Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return back()->with('error', 'Terjadi kesalahan saat menambahkan penjahit'); + } + } + + public function edit($id) + { + try { + $token = session('api_token'); + $tokenType = session('token_type'); + + if (!$token || !$tokenType) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $response = $this->apiService->get("api/users/tailors/{$id}"); + + if ($response->successful()) { + $data = $response->json(); + if (isset($data['data'])) { + $tailor = $data['data']; + return view('admin.tailors.edit', compact('tailor')); + } + } + + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $errorMessage = $response->json()['message'] ?? 'Unknown error'; + \Log::error('Tailor Edit Error:', [ + 'status' => $response->status(), + 'message' => $errorMessage, + 'id' => $id + ]); + + return back()->with('error', 'Gagal memuat data penjahit: ' . $errorMessage); + } catch (\Exception $e) { + \Log::error('Tailor Edit Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return back()->with('error', 'Terjadi kesalahan saat memuat data penjahit'); + } + } + + public function update(Request $request, $id) + { + try { + $token = session('api_token'); + $tokenType = session('token_type'); + + if (!$token || !$tokenType) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $response = $this->apiService->put("api/users/tailors/{$id}", $request->all()); + + if ($response->successful()) { + return redirect()->route('admin.tailors.index') + ->with('success', 'Data penjahit berhasil diperbarui'); + } + + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $errorMessage = $response->json()['message'] ?? 'Unknown error'; + \Log::error('Tailor Update Error:', [ + 'status' => $response->status(), + 'message' => $errorMessage, + 'id' => $id, + 'request' => $request->all() + ]); + + return back()->with('error', 'Gagal memperbarui data penjahit: ' . $errorMessage); + } catch (\Exception $e) { + \Log::error('Tailor Update Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return back()->with('error', 'Terjadi kesalahan saat memperbarui data penjahit'); + } + } + + public function destroy($id) + { + try { + $token = session('api_token'); + $tokenType = session('token_type'); + + if (!$token || !$tokenType) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $response = $this->apiService->delete("api/users/tailors/{$id}"); + + if ($response->successful()) { + return redirect()->route('admin.tailors.index') + ->with('success', 'Penjahit berhasil dihapus'); + } + + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + $errorMessage = $response->json()['message'] ?? 'Unknown error'; + \Log::error('Tailor Destroy Error:', [ + 'status' => $response->status(), + 'message' => $errorMessage, + 'id' => $id + ]); + + return back()->with('error', 'Gagal menghapus penjahit: ' . $errorMessage); + } catch (\Exception $e) { + \Log::error('Tailor Destroy Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return back()->with('error', 'Terjadi kesalahan saat menghapus penjahit'); + } + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Controllers/Admin/WithdrawalController.php b/TA_website/app/Http/Controllers/Admin/WithdrawalController.php new file mode 100644 index 0000000..a108c54 --- /dev/null +++ b/TA_website/app/Http/Controllers/Admin/WithdrawalController.php @@ -0,0 +1,257 @@ +apiService = $apiService; + } + + /** + * Display a listing of pending withdrawals. + * + * @return \Illuminate\Http\Response + */ + public function pending() + { + try { + $response = $this->apiService->get('admin/withdrawals/pending'); + + if ($response->successful()) { + $withdrawals = $response->json()['data'] ?? []; + return view('admin.withdrawals.pending', compact('withdrawals')); + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error lain + return back()->with('error', 'Gagal memuat data penarikan: ' . ($response->json()['message'] ?? 'Unknown error')); + + } catch (\Exception $e) { + Log::error('Withdrawal Pending Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->with('error', 'Terjadi kesalahan saat memuat data penarikan'); + } + } + + /** + * Display a listing of processed withdrawals history. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function history(Request $request) + { + try { + // Siapkan query parameters + $query = []; + + // Filter berdasarkan status + if ($request->filled('status')) { + $query['status'] = $request->status; + } + + // Pencarian + if ($request->filled('search')) { + $query['search'] = $request->search; + } + + // Filter rentang tanggal + if ($request->filled('from_date')) { + $query['from_date'] = $request->from_date; + } + + if ($request->filled('to_date')) { + $query['to_date'] = $request->to_date; + } + + // Pengurutan + if ($request->filled('sort_by')) { + $query['sort_by'] = $request->sort_by; + } + + if ($request->filled('sort_order')) { + $query['sort_order'] = $request->sort_order; + } + + // Paginasi + if ($request->filled('per_page')) { + $query['per_page'] = $request->per_page; + } + + // Halaman saat ini + if ($request->filled('page')) { + $query['page'] = $request->page; + } + + $response = $this->apiService->get('admin/withdrawals/history', $query); + + if ($response->successful()) { + $withdrawalHistory = $response->json()['data'] ?? []; + return view('admin.withdrawals.history', compact('withdrawalHistory')); + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error lain + return back()->with('error', 'Gagal memuat riwayat penarikan: ' . ($response->json()['message'] ?? 'Unknown error')); + + } catch (\Exception $e) { + Log::error('Withdrawal History Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->with('error', 'Terjadi kesalahan saat memuat riwayat penarikan'); + } + } + + /** + * Show the form for processing a withdrawal. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function showProcess($id) + { + try { + // Ambil semua data withdrawal pending + $response = $this->apiService->get('admin/withdrawals/pending'); + + if ($response->successful()) { + $withdrawals = $response->json()['data'] ?? []; + + // Cari withdrawal dengan ID yang sesuai + $withdrawal = null; + foreach ($withdrawals as $item) { + if ($item['id'] == $id) { + $withdrawal = $item; + break; + } + } + + if ($withdrawal) { + return view('admin.withdrawals.process', compact('withdrawal')); + } + + // Jika tidak ditemukan + return redirect()->route('admin.withdrawals.pending') + ->with('error', 'Penarikan dengan ID tersebut tidak ditemukan'); + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error lain + return redirect()->route('admin.withdrawals.pending') + ->with('error', 'Gagal memuat data penarikan: ' . ($response->json()['message'] ?? 'Unknown error')); + + } catch (\Exception $e) { + Log::error('Withdrawal Show Process Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return redirect()->route('admin.withdrawals.pending') + ->with('error', 'Terjadi kesalahan saat memuat data penarikan'); + } + } + + /** + * Process the specified withdrawal request. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function process(Request $request, $id) + { + try { + // Validasi request sesuai dengan API yang diupdate + $request->validate([ + 'status' => 'required|in:completed,rejected', + 'rejection_reason' => 'required_if:status,rejected', + 'proof_of_payment' => 'required_if:status,completed|file|mimes:jpeg,png,jpg,pdf|max:2048', + ]); + + // Persiapkan data untuk API + $data = [ + 'status' => $request->status, + 'rejection_reason' => $request->rejection_reason, + ]; + + // Siapkan file bukti pembayaran jika ada + if ($request->status === 'completed' && $request->hasFile('proof_of_payment')) { + $response = $this->apiService->post("admin/withdrawals/{$id}/process", $data, [ + 'proof_of_payment' => $request->file('proof_of_payment') + ]); + } else { + $response = $this->apiService->post("admin/withdrawals/{$id}/process", $data); + } + + if ($response->successful()) { + $statusMessage = $request->status === 'completed' ? 'diselesaikan' : 'ditolak'; + return redirect()->route('admin.withdrawals.pending') + ->with('success', "Penarikan berhasil {$statusMessage}"); + } + + // Jika response error 401, redirect ke login + if ($response->status() === 401) { + return redirect()->route('admin.login') + ->with('error', 'Sesi anda telah berakhir. Silakan login kembali.'); + } + + // Jika terjadi error validasi + if ($response->status() === 422) { + return back()->withErrors($response->json()['data'] ?? []) + ->withInput(); + } + + // Jika terjadi error lain + return back()->with('error', 'Gagal memproses penarikan: ' . ($response->json()['message'] ?? 'Unknown error')) + ->withInput(); + + } catch (\Exception $e) { + Log::error('Withdrawal Process Error:', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + return back()->with('error', 'Terjadi kesalahan saat memproses penarikan') + ->withInput(); + } + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Controllers/AdminController.php b/TA_website/app/Http/Controllers/AdminController.php new file mode 100644 index 0000000..b92ff0e --- /dev/null +++ b/TA_website/app/Http/Controllers/AdminController.php @@ -0,0 +1,54 @@ +validate([ + 'email' => ['required', 'email'], + 'password' => ['required'], + ]); + + $user = User::where('email', $credentials['email'])->first(); + + if (!$user || $user->role !== 'admin') { + return back()->withErrors([ + 'email' => 'These credentials do not have admin access.', + ]); + } + + if (Auth::attempt($credentials)) { + $request->session()->regenerate(); + + // Update last login time - REMOVED as requested + // $user->update([ + // 'last_login_at' => now() + // ]); + + return redirect()->intended('admin/dashboard'); + } + + return back()->withErrors([ + 'email' => 'The provided credentials do not match our records.', + ]); + } + + public function logout(Request $request) + { + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + return redirect('/admin/login'); + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Controllers/Controller.php b/TA_website/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..8677cd5 --- /dev/null +++ b/TA_website/app/Http/Controllers/Controller.php @@ -0,0 +1,8 @@ +role !== 'admin') { + + // Periksa juga apakah token API masih ada + $token = session('api_token'); + $tokenType = session('token_type'); + $userData = session('user_data'); + + // Jika tidak ada token atau user data + if (!$token || !$tokenType || !$userData || !isset($userData['role']) || $userData['role'] !== 'admin') { + return redirect()->route('admin.login') + ->with('error', 'Anda harus login sebagai admin untuk mengakses halaman ini.'); + } + + // Jika ada token API dan role admin di session, izinkan akses + if ($token && $tokenType && isset($userData['role']) && $userData['role'] === 'admin') { + return $next($request); + } + + return redirect()->route('admin.login'); + } + + return $next($request); + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Middleware/Authenticate.php b/TA_website/app/Http/Middleware/Authenticate.php new file mode 100644 index 0000000..389c0e9 --- /dev/null +++ b/TA_website/app/Http/Middleware/Authenticate.php @@ -0,0 +1,20 @@ +expectsJson()) { + return '/admin/login'; + } + return null; + } +} \ No newline at end of file diff --git a/TA_website/app/Http/Middleware/RedirectIfAuthenticated.php b/TA_website/app/Http/Middleware/RedirectIfAuthenticated.php new file mode 100644 index 0000000..76bed5e --- /dev/null +++ b/TA_website/app/Http/Middleware/RedirectIfAuthenticated.php @@ -0,0 +1,30 @@ +check()) { + return redirect(RouteServiceProvider::HOME); + } + } + + return $next($request); + } +} \ No newline at end of file diff --git a/TA_website/app/Models/Booking.php b/TA_website/app/Models/Booking.php new file mode 100644 index 0000000..d24f05e --- /dev/null +++ b/TA_website/app/Models/Booking.php @@ -0,0 +1,42 @@ + 'datetime', + 'total_price' => 'decimal:2' + ]; + + public function customer(): BelongsTo + { + return $this->belongsTo(User::class, 'customer_id'); + } + + public function tailor(): BelongsTo + { + return $this->belongsTo(User::class, 'tailor_id'); + } + + public function measurement(): BelongsTo + { + return $this->belongsTo(Measurement::class); + } +} \ No newline at end of file diff --git a/TA_website/app/Models/Measurement.php b/TA_website/app/Models/Measurement.php new file mode 100644 index 0000000..551674a --- /dev/null +++ b/TA_website/app/Models/Measurement.php @@ -0,0 +1,49 @@ + + */ + protected $fillable = [ + 'customer_id', + 'height', + 'weight', + 'shoulder', + 'chest', + 'waist', + 'hip', + 'sleeve', + 'neck', + 'notes' + ]; + + protected $casts = [ + 'height' => 'decimal:2', + 'weight' => 'decimal:2', + 'shoulder' => 'decimal:2', + 'chest' => 'decimal:2', + 'waist' => 'decimal:2', + 'hip' => 'decimal:2', + 'sleeve' => 'decimal:2', + 'neck' => 'decimal:2' + ]; + + /** + * Get the customer that owns the measurement. + */ + public function customer(): BelongsTo + { + return $this->belongsTo(User::class, 'customer_id'); + } +} \ No newline at end of file diff --git a/TA_website/app/Models/Order.php b/TA_website/app/Models/Order.php new file mode 100644 index 0000000..e4824be --- /dev/null +++ b/TA_website/app/Models/Order.php @@ -0,0 +1,42 @@ + + */ + protected $fillable = [ + 'customer_id', + 'status', + 'total', + 'payment_status', + 'notes', + ]; + + /** + * Get the customer that owns the order. + */ + public function customer() + { + return $this->belongsTo(User::class, 'customer_id'); + } + + /** + * Get the products for the order. + */ + public function products() + { + return $this->belongsToMany(Product::class, 'order_products') + ->withPivot('quantity', 'price', 'total') + ->withTimestamps(); + } +} \ No newline at end of file diff --git a/TA_website/app/Models/Product.php b/TA_website/app/Models/Product.php new file mode 100644 index 0000000..0e5d2a8 --- /dev/null +++ b/TA_website/app/Models/Product.php @@ -0,0 +1,41 @@ + + */ + protected $fillable = [ + 'name', + 'description', + 'price', + 'image', + 'category', + 'stock', + 'status' + ]; + + protected $casts = [ + 'price' => 'decimal:2', + 'stock' => 'integer' + ]; + + /** + * Get the orders for the product. + */ + public function orders() + { + return $this->belongsToMany(Order::class, 'order_products') + ->withPivot('quantity', 'price', 'total') + ->withTimestamps(); + } +} \ No newline at end of file diff --git a/TA_website/app/Models/TailorGallery.php b/TA_website/app/Models/TailorGallery.php new file mode 100644 index 0000000..da389e2 --- /dev/null +++ b/TA_website/app/Models/TailorGallery.php @@ -0,0 +1,24 @@ +belongsTo(User::class, 'user_id'); + } +} \ No newline at end of file diff --git a/TA_website/app/Models/TailorRating.php b/TA_website/app/Models/TailorRating.php new file mode 100644 index 0000000..6561080 --- /dev/null +++ b/TA_website/app/Models/TailorRating.php @@ -0,0 +1,38 @@ + 'decimal:1' + ]; + + public function booking() + { + return $this->belongsTo(Booking::class); + } + + public function customer() + { + return $this->belongsTo(User::class, 'customer_id'); + } + + public function tailor() + { + return $this->belongsTo(User::class, 'tailor_id'); + } +} \ No newline at end of file diff --git a/TA_website/app/Models/User.php b/TA_website/app/Models/User.php new file mode 100644 index 0000000..c3cd682 --- /dev/null +++ b/TA_website/app/Models/User.php @@ -0,0 +1,89 @@ + */ + use HasApiTokens, HasFactory, Notifiable; + + /** + * The attributes that are mass assignable. + * + * @var list + */ + protected $fillable = [ + 'name', + 'email', + 'password', + 'phone', + 'address', + 'role', + 'last_login_at', + 'phone_number', + 'latitude', + 'longitude', + 'shop_description', + 'profile_photo', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var list + */ + protected $hidden = [ + 'password', + 'remember_token', + ]; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + 'last_login_at' => 'datetime', + 'latitude' => 'decimal:7', + 'longitude' => 'decimal:7', + ]; + } + + /** + * Get the orders for the user. + */ + public function orders() + { + return $this->hasMany(Booking::class, 'customer_id'); + } + + public function bookings() + { + return $this->hasMany(Booking::class, 'tailor_id'); + } + + public function galleries() + { + return $this->hasMany(TailorGallery::class); + } + + public function reviews() + { + return $this->hasMany(TailorRating::class, 'tailor_id'); + } + + public function specializations() + { + return $this->belongsToMany(TailorSpecialization::class); + } +} diff --git a/TA_website/app/Providers/ApiServiceProvider.php b/TA_website/app/Providers/ApiServiceProvider.php new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/TA_website/app/Providers/ApiServiceProvider.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/TA_website/app/Providers/AppServiceProvider.php b/TA_website/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..8d25cec --- /dev/null +++ b/TA_website/app/Providers/AppServiceProvider.php @@ -0,0 +1,28 @@ +app->singleton(ApiService::class, function ($app) { + return new ApiService(); + }); + } + + /** + * Bootstrap any application services. + */ + public function boot(): void + { + // + } +} diff --git a/TA_website/app/Providers/RouteServiceProvider.php b/TA_website/app/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..86bd95a --- /dev/null +++ b/TA_website/app/Providers/RouteServiceProvider.php @@ -0,0 +1,40 @@ +by($request->user()?->id ?: $request->ip()); + }); + + $this->routes(function () { + Route::middleware('api') + ->prefix('api') + ->group(base_path('routes/api.php')); + + Route::middleware('web') + ->group(base_path('routes/web.php')); + }); + } +} \ No newline at end of file diff --git a/TA_website/app/Services/ApiService.php b/TA_website/app/Services/ApiService.php new file mode 100644 index 0000000..f723d22 --- /dev/null +++ b/TA_website/app/Services/ApiService.php @@ -0,0 +1,171 @@ +baseUrl = config('api.url'); + } + + /** + * Get full API URL + * + * @param string $path + * @return string + */ + public function url($path = '') + { + // Remove leading slash if present + $path = ltrim($path, '/'); + + // API URL yang benar adalah https://api.tailors.stuffly.my.id/api/admin/login + // Format yang benar adalah dengan menambahkan 'api/' di depan path + + // Handle base URL with or without trailing slash + $baseUrl = rtrim($this->baseUrl, '/'); + + // Tambahkan prefiks 'api/' jika belum ada + if (strpos($path, 'api/') !== 0) { + $path = "api/{$path}"; + } + + return "{$baseUrl}/{$path}"; + } + + /** + * Get Http client with authorization headers + * + * @return \Illuminate\Http\Client\PendingRequest + */ + public function http() + { + $token = session('api_token'); + $tokenType = session('token_type'); + + return Http::withHeaders([ + 'Authorization' => $token && $tokenType ? "{$tokenType} {$token}" : '', + 'Accept' => 'application/json', + ])->withOptions([ + 'verify' => false, // Disable SSL verification for development + ]); + } + + /** + * Perform GET request + * + * @param string $path + * @param array $params + * @return \Illuminate\Http\Client\Response + */ + public function get($path, array $params = []) + { + $url = $this->url($path); + \Log::debug("API GET Request", [ + 'url' => $url, + 'params' => $params + ]); + + $response = $this->http()->get($url, $params); + + \Log::debug("API GET Response", [ + 'status' => $response->status(), + 'body' => $response->json() + ]); + + return $response; + } + + /** + * Perform POST request + * + * @param string $path + * @param array $data + * @param array $files + * @return \Illuminate\Http\Client\Response + */ + public function post($path, array $data = [], array $files = []) + { + $url = $this->url($path); + \Log::debug("API POST Request", [ + 'url' => $url, + 'data' => $data + ]); + + // Jika ada file, gunakan multipart/form-data + if (!empty($files)) { + $response = $this->httpMultipart($files)->post($url, $data); + } else { + $response = $this->http()->post($url, $data); + } + + \Log::debug("API POST Response", [ + 'status' => $response->status(), + 'body' => $response->json() + ]); + + return $response; + } + + /** + * Get Http client with headers for multipart/form-data (file uploads) + * + * @return \Illuminate\Http\Client\PendingRequest + */ + protected function httpMultipart($files = []) + { + $token = session('api_token'); + $tokenType = session('token_type'); + + $client = Http::withHeaders([ + 'Authorization' => $token && $tokenType ? "{$tokenType} {$token}" : '', + 'Accept' => 'application/json', + ])->withOptions([ + 'verify' => false, // Disable SSL verification for development + ]); + + // Tambahkan file ke request + foreach ($files as $name => $file) { + $client = $client->attach($name, file_get_contents($file->path()), $file->getClientOriginalName()); + } + + return $client; + } + + /** + * Perform PUT request + * + * @param string $path + * @param array $data + * @return \Illuminate\Http\Client\Response + */ + public function put($path, array $data = []) + { + return $this->http()->put($this->url($path), $data); + } + + /** + * Perform DELETE request + * + * @param string $path + * @param array $params + * @return \Illuminate\Http\Client\Response + */ + public function delete($path, array $params = []) + { + return $this->http()->delete($this->url($path), $params); + } +} \ No newline at end of file diff --git a/TA_website/artisan b/TA_website/artisan new file mode 100644 index 0000000..c35e31d --- /dev/null +++ b/TA_website/artisan @@ -0,0 +1,18 @@ +#!/usr/bin/env php +handleCommand(new ArgvInput); + +exit($status); diff --git a/TA_website/bootstrap/app.php b/TA_website/bootstrap/app.php new file mode 100644 index 0000000..eeaadd3 --- /dev/null +++ b/TA_website/bootstrap/app.php @@ -0,0 +1,20 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware) { + $middleware->alias([ + 'admin' => \App\Http\Middleware\AdminMiddleware::class, + ]); + }) + ->withExceptions(function (Exceptions $exceptions) { + // + })->create(); diff --git a/TA_website/bootstrap/cache/.gitignore b/TA_website/bootstrap/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/bootstrap/providers.php b/TA_website/bootstrap/providers.php new file mode 100644 index 0000000..38b258d --- /dev/null +++ b/TA_website/bootstrap/providers.php @@ -0,0 +1,5 @@ +=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.0.10", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.10" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2024-02-18T20:23:39+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "8c784d071debd117328803d86b2097615b457500" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", + "reference": "8c784d071debd117328803d86b2097615b457500", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.0" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2024-10-09T13:47:03+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2025-03-06T22:45:56+00:00" + }, + { + "name": "fruitcake/php-cors", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "symfony/http-foundation": "^4.4|^5.4|^6|^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barryvdh", + "email": "barryvdh@gmail.com" + } + ], + "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", + "homepage": "https://github.com/fruitcake/php-cors", + "keywords": [ + "cors", + "laravel", + "symfony" + ], + "support": { + "issues": "https://github.com/fruitcake/php-cors/issues", + "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2023-10-12T05:21:21+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:37:11+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.2.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:27:01+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:30:47+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "uri-template/tests": "1.0.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\UriTemplate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + } + ], + "description": "A polyfill class for uri_template of PHP", + "keywords": [ + "guzzlehttp", + "uri-template" + ], + "support": { + "issues": "https://github.com/guzzle/uri-template/issues", + "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/uri-template", + "type": "tidelift" + } + ], + "time": "2025-02-03T10:55:03+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.7.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "a4ba76e06fe6dd02312359f8184ab259900a7780" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/a4ba76e06fe6dd02312359f8184ab259900a7780", + "reference": "a4ba76e06fe6dd02312359f8184ab259900a7780", + "shasum": "" + }, + "require": { + "brick/math": "^0.11|^0.12", + "composer-runtime-api": "^2.2", + "doctrine/inflector": "^2.0.5", + "dragonmantank/cron-expression": "^3.4", + "egulias/email-validator": "^3.2.1|^4.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-session": "*", + "ext-tokenizer": "*", + "fruitcake/php-cors": "^1.3", + "guzzlehttp/guzzle": "^7.8.2", + "guzzlehttp/uri-template": "^1.0", + "laravel/prompts": "^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "league/commonmark": "^2.6", + "league/flysystem": "^3.25.1", + "league/flysystem-local": "^3.25.1", + "league/uri": "^7.5.1", + "monolog/monolog": "^3.0", + "nesbot/carbon": "^3.8.4", + "nunomaduro/termwind": "^2.0", + "php": "^8.2", + "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", + "symfony/polyfill-php83": "^1.31", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.5", + "vlucas/phpdotenv": "^5.6.1", + "voku/portable-ascii": "^2.0.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "psr/log-implementation": "1.0|2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/collections": "self.version", + "illuminate/concurrency": "self.version", + "illuminate/conditionable": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/macroable": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/process": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/testing": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "spatie/once": "*" + }, + "require-dev": { + "ably/ably-php": "^1.0", + "aws/aws-sdk-php": "^3.322.9", + "ext-gmp": "*", + "fakerphp/faker": "^1.24", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", + "league/flysystem-aws-s3-v3": "^3.25.1", + "league/flysystem-ftp": "^3.25.1", + "league/flysystem-path-prefixing": "^3.25.1", + "league/flysystem-read-only": "^3.25.1", + "league/flysystem-sftp-v3": "^3.25.1", + "mockery/mockery": "^1.6.10", + "orchestra/testbench-core": "^10.0.0", + "pda/pheanstalk": "^5.0.6", + "php-http/discovery": "^1.15", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3", + "resend/resend-php": "^0.10.0", + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" + }, + "suggest": { + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", + "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", + "ext-apcu": "Required to use the APC cache driver.", + "ext-fileinfo": "Required to use the Filesystem class.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", + "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.", + "ext-pdo": "Required to use all database features.", + "ext-posix": "Required to use all features of the queue worker.", + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", + "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).", + "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", + "mockery/mockery": "Required to use mocking (^1.6).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", + "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).", + "predis/predis": "Required to use the predis connector (^2.3).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", + "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Collections/functions.php", + "src/Illuminate/Collections/helpers.php", + "src/Illuminate/Events/functions.php", + "src/Illuminate/Filesystem/functions.php", + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Log/functions.php", + "src/Illuminate/Support/functions.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/", + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-04-03T18:00:49+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.3.5", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/console": "^6.2|^7.0" + }, + "conflict": { + "illuminate/console": ">=10.17.0 <10.25.0", + "laravel/framework": ">=10.17.0 <10.25.0" + }, + "require-dev": { + "illuminate/collections": "^10.0|^11.0|^12.0", + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3|^3.4", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-mockery": "^1.1" + }, + "suggest": { + "ext-pcntl": "Required for the spinner to be animated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.3.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Laravel\\Prompts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Add beautiful and user-friendly forms to your command-line applications.", + "support": { + "issues": "https://github.com/laravel/prompts/issues", + "source": "https://github.com/laravel/prompts/tree/v0.3.5" + }, + "time": "2025-02-11T13:34:40+00:00" + }, + { + "name": "laravel/sanctum", + "version": "v4.0.8", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/ec1dd9ddb2ab370f79dfe724a101856e0963f43c", + "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^11.0|^12.0", + "illuminate/contracts": "^11.0|^12.0", + "illuminate/database": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "php": "^8.2", + "symfony/console": "^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "orchestra/testbench": "^9.0|^10.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2025-01-26T19:34:36+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2025-03-19T13:51:03+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.10.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "php": "^7.2.5|^8.0", + "psy/psysh": "^0.11.1|^0.12.0", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" + }, + "require-dev": { + "mockery/mockery": "~1.3.3|^1.4.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "support": { + "issues": "https://github.com/laravel/tinker/issues", + "source": "https://github.com/laravel/tinker/tree/v2.10.1" + }, + "time": "2025-01-27T14:24:01+00:00" + }, + { + "name": "league/commonmark", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d990688c91cedfb69753ffc2512727ec646df2ad", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2024-12-29T14:10:59+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "league/flysystem", + "version": "3.29.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319", + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.29.1" + }, + "time": "2024-10-08T08:58:34+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.29.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0" + }, + "time": "2024-08-09T21:24:39+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-09-21T08:32:55+00:00" + }, + { + "name": "league/uri", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "league/uri-components": "Needed to easily manipulate URI objects components", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:18:47+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.9.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2025-03-24T10:02:05+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.9.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "6d16a8a015166fe54e22c042e0805c5363aef50d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/6d16a8a015166fe54e22c042e0805c5363aef50d", + "reference": "6d16a8a015166fe54e22c042e0805c5363aef50d", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3 || ^7.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.57.2", + "kylekatarnls/multi-tester": "^2.5.3", + "ondrejmirtes/better-reflection": "^6.25.0.4", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.11.2", + "phpunit/phpunit": "^10.5.20", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:57:33+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.5.2", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.2" + }, + "time": "2024-10-06T23:10:23+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.6", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "ce708655043c7050eb050df361c5e313cf708309" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/ce708655043c7050eb050df361c5e313cf708309", + "reference": "ce708655043c7050eb050df361c5e313cf708309", + "shasum": "" + }, + "require": { + "php": "8.0 - 8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.6" + }, + "time": "2025-03-30T21:06:30+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/52915afe6a1044e8b9cee1bcff836fb63acf9cda", + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.1.8" + }, + "require-dev": { + "illuminate/console": "^11.33.2", + "laravel/pint": "^1.18.2", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0", + "phpstan/phpstan": "^1.12.11", + "phpstan/phpstan-strict-rules": "^1.6.1", + "symfony/var-dumper": "^7.1.8", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Its like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2024-11-21T10:39:51+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:41:07+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.12.8", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": false, + "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.8" + }, + "time": "2025-03-16T03:05:19+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/collection", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.1.1" + }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.7.6", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", + "ext-json": "*", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.8", + "ergebnis/composer-normalize": "^2.15", + "mockery/mockery": "^1.3", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", + "php-mock/php-mock-mockery": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.7.6" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "time": "2024-04-27T21:32:50+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/console", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "e51498ea18570c062e7df29d05a7003585b19b88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88", + "reference": "e51498ea18570c062e7df29d05a7003585b19b88", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-12T08:11:12+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b", + "reference": "102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-03T07:12:39+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:17+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "371272aeb6286f8135e028ca535f8e4d6f114126" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/371272aeb6286f8135e028ca535f8e4d6f114126", + "reference": "371272aeb6286f8135e028ca535f8e4d6f114126", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-25T15:54:33+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "b1fe91bc1fa454a806d3f98db4ba826eb9941a54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b1fe91bc1fa454a806d3f98db4ba826eb9941a54", + "reference": "b1fe91bc1fa454a806d3f98db4ba826eb9941a54", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^7.1", + "symfony/routing": "^6.4|^7.0", + "symfony/serializer": "^7.1", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-28T13:32:50+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f3871b182c44997cf039f3b462af4a48fb85f9d3", + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/mime": "^7.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-27T11:08:17+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/87ca22046b78c3feaff04b337f33b38510fd686b", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-19T08:51:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-13T12:21:46+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/ee9a67edc6baa33e5fae662f94f91fd262930996", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T10:56:55+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-13T13:31:26+00:00" + }, + { + "name": "symfony/translation", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/283856e6981286cc0d800b53bd5703e8e363f05a", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^4.18|^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-13T10:27:23+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/82b478c69745d8878eb60f9a049a4d584996f73a", + "reference": "82b478c69745d8878eb60f9a049a4d584996f73a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T11:39:41+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + }, + "time": "2024-12-21T16:25:41+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:52:34+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "https://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2024-11-21T01:49:47+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "packages-dev": [ + { + "name": "barryvdh/laravel-ide-helper", + "version": "v3.5.5", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-ide-helper.git", + "reference": "8d441ec99f8612b942b55f5183151d91591b618a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/8d441ec99f8612b942b55f5183151d91591b618a", + "reference": "8d441ec99f8612b942b55f5183151d91591b618a", + "shasum": "" + }, + "require": { + "barryvdh/reflection-docblock": "^2.3", + "composer/class-map-generator": "^1.0", + "ext-json": "*", + "illuminate/console": "^11.15 || ^12", + "illuminate/database": "^11.15 || ^12", + "illuminate/filesystem": "^11.15 || ^12", + "illuminate/support": "^11.15 || ^12", + "php": "^8.2" + }, + "require-dev": { + "ext-pdo_sqlite": "*", + "friendsofphp/php-cs-fixer": "^3", + "illuminate/config": "^11.15 || ^12", + "illuminate/view": "^11.15 || ^12", + "mockery/mockery": "^1.4", + "orchestra/testbench": "^9.2 || ^10", + "phpunit/phpunit": "^10.5 || ^11.5.3", + "spatie/phpunit-snapshot-assertions": "^4 || ^5", + "vimeo/psalm": "^5.4", + "vlucas/phpdotenv": "^5" + }, + "suggest": { + "illuminate/events": "Required for automatic helper generation (^6|^7|^8|^9|^10|^11)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\LaravelIdeHelper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.", + "keywords": [ + "autocomplete", + "codeintel", + "dev", + "helper", + "ide", + "laravel", + "netbeans", + "phpdoc", + "phpstorm", + "sublime" + ], + "support": { + "issues": "https://github.com/barryvdh/laravel-ide-helper/issues", + "source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.5.5" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2025-02-11T13:59:46+00:00" + }, + { + "name": "barryvdh/reflection-docblock", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/ReflectionDocBlock.git", + "reference": "b6ff9f93603561f50e53b64310495d20b8dff5d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/b6ff9f93603561f50e53b64310495d20b8dff5d8", + "reference": "b6ff9f93603561f50e53b64310495d20b8dff5d8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.14|^9" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Barryvdh": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "support": { + "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.3.1" + }, + "time": "2025-01-18T19:26:32+00:00" + }, + { + "name": "composer/class-map-generator", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/composer/class-map-generator.git", + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/134b705ddb0025d397d8318a75825fe3c9d1da34", + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34", + "shasum": "" + }, + "require": { + "composer/pcre": "^2.1 || ^3.1", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\ClassMapGenerator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Utilities to scan PHP code and generate class maps.", + "keywords": [ + "classmap" + ], + "support": { + "issues": "https://github.com/composer/class-map-generator/issues", + "source": "https://github.com/composer/class-map-generator/tree/1.6.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-03-24T13:50:44+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "fakerphp/faker", + "version": "v1.24.1", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1" + }, + "time": "2024-11-21T13:46:39+00:00" + }, + { + "name": "filp/whoops", + "version": "2.18.0", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e", + "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.0" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-03-15T12:00:00+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1" + }, + "time": "2020-07-09T08:09:16+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "f31f4980f52be17c4667f3eafe034e6826787db2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/f31f4980f52be17c4667f3eafe034e6826787db2", + "reference": "f31f4980f52be17c4667f3eafe034e6826787db2", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0|^12.0", + "illuminate/contracts": "^10.24|^11.0|^12.0", + "illuminate/log": "^10.24|^11.0|^12.0", + "illuminate/process": "^10.24|^11.0|^12.0", + "illuminate/support": "^10.24|^11.0|^12.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.0", + "laravel/pint": "^1.13", + "orchestra/testbench-core": "^8.13|^9.0|^10.0", + "pestphp/pest": "^2.20|^3.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0", + "phpstan/phpstan": "^1.10", + "symfony/var-dumper": "^6.3|^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2025-01-28T15:15:15+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.21.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "370772e7d9e9da087678a0edf2b11b6960e40558" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/370772e7d9e9da087678a0edf2b11b6960e40558", + "reference": "370772e7d9e9da087678a0edf2b11b6960e40558", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.72.0", + "illuminate/view": "^11.44.2", + "larastan/larastan": "^3.2.0", + "laravel-zero/framework": "^11.36.1", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3", + "pestphp/pest": "^2.36.0" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2025-03-14T22:31:42+00:00" + }, + { + "name": "laravel/sail", + "version": "v1.41.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/sail.git", + "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sail/zipball/fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec", + "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0", + "symfony/yaml": "^6.0|^7.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "phpstan/phpstan": "^1.10" + }, + "bin": [ + "bin/sail" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sail\\SailServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Docker files for running a basic Laravel application.", + "keywords": [ + "docker", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/sail/issues", + "source": "https://github.com/laravel/sail" + }, + "time": "2025-01-24T15:45:36+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-02-12T12:17:51+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.8.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/4cf9f3b47afff38b139fb79ce54fc71799022ce8", + "reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.18.0", + "nunomaduro/termwind": "^2.3.0", + "php": "^8.2.0", + "symfony/console": "^7.2.5" + }, + "conflict": { + "laravel/framework": "<11.44.2 || >=13.0.0", + "phpunit/phpunit": "<11.5.15 || >=13.0.0" + }, + "require-dev": { + "brianium/paratest": "^7.8.3", + "larastan/larastan": "^3.2", + "laravel/framework": "^11.44.2 || ^12.6", + "laravel/pint": "^1.21.2", + "laravel/sail": "^1.41.0", + "laravel/sanctum": "^4.0.8", + "laravel/tinker": "^2.10.1", + "orchestra/testbench-core": "^9.12.0 || ^10.1", + "pestphp/pest": "^3.8.0", + "sebastian/environment": "^7.2.0 || ^8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-04-03T14:33:09+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.0", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.2" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-25T13:26:39+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-27T05:02:59+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.17", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "fd2e863a2995cdfd864fb514b5e0b28b09895b5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fd2e863a2995cdfd864fb514b5e0b28b09895b5c", + "reference": "fd2e863a2995cdfd864fb514b5e0b28b09895b5c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.9", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.1", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.0", + "sebastian/exporter": "^6.3.0", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.2", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.17" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-04-08T07:59:11+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-07T06:57:01+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:54:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-05T09:17:50+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:10:34+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-18T13:35:50+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912", + "reference": "4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-03T07:12:39+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.2" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/TA_website/config/api.php b/TA_website/config/api.php new file mode 100644 index 0000000..fdc8598 --- /dev/null +++ b/TA_website/config/api.php @@ -0,0 +1,24 @@ + env('API_URL', 'https://api.tailors.stuffly.my.id'), + + /* + |-------------------------------------------------------------------------- + | API Timeout + |-------------------------------------------------------------------------- + | + | The timeout in seconds for API requests + | + */ + 'timeout' => env('API_TIMEOUT', 60), +]; diff --git a/TA_website/config/app.php b/TA_website/config/app.php new file mode 100644 index 0000000..324b513 --- /dev/null +++ b/TA_website/config/app.php @@ -0,0 +1,126 @@ + env('APP_NAME', 'Laravel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | the application so that it's available within Artisan commands. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. The timezone + | is set to "UTC" by default as it is suitable for most use cases. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by Laravel's translation / localization methods. This option can be + | set to any locale for which you plan to have translation strings. + | + */ + + 'locale' => env('APP_LOCALE', 'en'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), + + 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. + | + */ + + 'cipher' => 'AES-256-CBC', + + 'key' => env('APP_KEY'), + + 'previous_keys' => [ + ...array_filter( + explode(',', env('APP_PREVIOUS_KEYS', '')) + ), + ], + + /* + |-------------------------------------------------------------------------- + | Maintenance Mode Driver + |-------------------------------------------------------------------------- + | + | These configuration options determine the driver used to determine and + | manage Laravel's "maintenance mode" status. The "cache" driver will + | allow maintenance mode to be controlled across multiple machines. + | + | Supported drivers: "file", "cache" + | + */ + + 'maintenance' => [ + 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), + 'store' => env('APP_MAINTENANCE_STORE', 'database'), + ], + +]; diff --git a/TA_website/config/auth.php b/TA_website/config/auth.php new file mode 100644 index 0000000..37f5afb --- /dev/null +++ b/TA_website/config/auth.php @@ -0,0 +1,127 @@ + [ + 'guard' => 'web', + 'passwords' => 'users', + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | here which uses session storage and the Eloquent user provider. + | + | All authentication drivers have a user provider. This defines how the + | users are actually retrieved out of your database or other storage + | mechanisms used by this application to persist your user's data. + | + | Supported: "session" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + ], + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication drivers have a user provider. This defines how the + | users are actually retrieved out of your database or other storage + | mechanisms used by this application to persist your user's data. + | + | If you have multiple user tables or models you may configure multiple + | sources which represent each model / table. These sources may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => App\Models\User::class, + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | You may specify multiple password reset configurations if you have more + | than one user table or model in the application and you want to have + | separate password reset settings based on the specific user types. + | + | The expiry time is the number of minutes that each reset token will be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + | The throttle setting is the number of seconds a user must wait before + | generating more password reset tokens. This prevents the user from + | quickly generating a very large amount of password reset tokens. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => 'password_reset_tokens', + 'expire' => 60, + 'throttle' => 60, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Password Confirmation Timeout + |-------------------------------------------------------------------------- + | + | Here you may define the amount of seconds before a password confirmation + | times out and the user is prompted to re-enter their password via the + | confirmation screen. By default, the timeout lasts for three hours. + | + */ + + 'password_timeout' => 10800, + + /* + |-------------------------------------------------------------------------- + | Login Route + |-------------------------------------------------------------------------- + | + | Here you may specify the route name that should be used when redirecting + | unauthenticated users. This is used by the authentication middleware. + | + */ + + 'login_route' => 'admin.login', + +]; diff --git a/TA_website/config/cache.php b/TA_website/config/cache.php new file mode 100644 index 0000000..925f7d2 --- /dev/null +++ b/TA_website/config/cache.php @@ -0,0 +1,108 @@ + env('CACHE_STORE', 'database'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + | Supported drivers: "array", "database", "file", "memcached", + | "redis", "dynamodb", "octane", "null" + | + */ + + 'stores' => [ + + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_CACHE_CONNECTION'), + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), + 'lock_table' => env('DB_CACHE_LOCK_TABLE'), + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + 'lock_path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), + 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), + ], + + 'dynamodb' => [ + 'driver' => 'dynamodb', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), + 'endpoint' => env('DYNAMODB_ENDPOINT'), + ], + + 'octane' => [ + 'driver' => 'octane', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing the APC, database, memcached, Redis, and DynamoDB cache + | stores, there might be other applications using the same cache. For + | that reason, you may prefix every cache key to avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), + +]; diff --git a/TA_website/config/database.php b/TA_website/config/database.php new file mode 100644 index 0000000..8910562 --- /dev/null +++ b/TA_website/config/database.php @@ -0,0 +1,174 @@ + env('DB_CONNECTION', 'sqlite'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Below are all of the database connections defined for your application. + | An example configuration is provided for each database system which + | is supported by Laravel. You're free to add / remove connections. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DB_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + 'busy_timeout' => null, + 'journal_mode' => null, + 'synchronous' => null, + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'mariadb' => [ + 'driver' => 'mariadb', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + // 'encrypt' => env('DB_ENCRYPT', 'yes'), + // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run on the database. + | + */ + + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as Memcached. You may define your connection settings here. + | + */ + + 'redis' => [ + + 'client' => env('REDIS_CLIENT', 'phpredis'), + + 'options' => [ + 'cluster' => env('REDIS_CLUSTER', 'redis'), + 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), + 'persistent' => env('REDIS_PERSISTENT', false), + ], + + 'default' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_DB', '0'), + ], + + 'cache' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_CACHE_DB', '1'), + ], + + ], + +]; diff --git a/TA_website/config/filesystems.php b/TA_website/config/filesystems.php new file mode 100644 index 0000000..3d671bd --- /dev/null +++ b/TA_website/config/filesystems.php @@ -0,0 +1,80 @@ + env('FILESYSTEM_DISK', 'local'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Below you may configure as many filesystem disks as necessary, and you + | may even configure multiple disks for the same driver. Examples for + | most supported storage drivers are configured here for reference. + | + | Supported drivers: "local", "ftp", "sftp", "s3" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app/private'), + 'serve' => true, + 'throw' => false, + 'report' => false, + ], + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', + 'throw' => false, + 'report' => false, + ], + + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + 'url' => env('AWS_URL'), + 'endpoint' => env('AWS_ENDPOINT'), + 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), + 'throw' => false, + 'report' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Symbolic Links + |-------------------------------------------------------------------------- + | + | Here you may configure the symbolic links that will be created when the + | `storage:link` Artisan command is executed. The array keys should be + | the locations of the links and the values should be their targets. + | + */ + + 'links' => [ + public_path('storage') => storage_path('app/public'), + ], + +]; diff --git a/TA_website/config/logging.php b/TA_website/config/logging.php new file mode 100644 index 0000000..1345f6f --- /dev/null +++ b/TA_website/config/logging.php @@ -0,0 +1,132 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Deprecations Log Channel + |-------------------------------------------------------------------------- + | + | This option controls the log channel that should be used to log warnings + | regarding deprecated PHP and library features. This allows you to get + | your application ready for upcoming major versions of dependencies. + | + */ + + 'deprecations' => [ + 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), + 'trace' => env('LOG_DEPRECATIONS_TRACE', false), + ], + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Laravel + | utilizes the Monolog PHP logging library, which includes a variety + | of powerful log handlers and formatters that you're free to use. + | + | Available drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", "custom", "stack" + | + */ + + 'channels' => [ + + 'stack' => [ + 'driver' => 'stack', + 'channels' => explode(',', env('LOG_STACK', 'single')), + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => env('LOG_DAILY_DAYS', 14), + 'replace_placeholders' => true, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), + 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), + 'level' => env('LOG_LEVEL', 'critical'), + 'replace_placeholders' => true, + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => StreamHandler::class, + 'handler_with' => [ + 'stream' => 'php://stderr', + ], + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), + 'replace_placeholders' => true, + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/laravel.log'), + ], + + ], + +]; diff --git a/TA_website/config/mail.php b/TA_website/config/mail.php new file mode 100644 index 0000000..756305b --- /dev/null +++ b/TA_website/config/mail.php @@ -0,0 +1,116 @@ + env('MAIL_MAILER', 'log'), + + /* + |-------------------------------------------------------------------------- + | Mailer Configurations + |-------------------------------------------------------------------------- + | + | Here you may configure all of the mailers used by your application plus + | their respective settings. Several examples have been configured for + | you and you are free to add your own as your application requires. + | + | Laravel supports a variety of mail "transport" drivers that can be used + | when delivering an email. You may specify which one you're using for + | your mailers below. You may also add additional mailers if needed. + | + | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", + | "postmark", "resend", "log", "array", + | "failover", "roundrobin" + | + */ + + 'mailers' => [ + + 'smtp' => [ + 'transport' => 'smtp', + 'scheme' => env('MAIL_SCHEME'), + 'url' => env('MAIL_URL'), + 'host' => env('MAIL_HOST', '127.0.0.1'), + 'port' => env('MAIL_PORT', 2525), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'postmark' => [ + 'transport' => 'postmark', + // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), + // 'client' => [ + // 'timeout' => 5, + // ], + ], + + 'resend' => [ + 'transport' => 'resend', + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), + ], + + 'log' => [ + 'transport' => 'log', + 'channel' => env('MAIL_LOG_CHANNEL'), + ], + + 'array' => [ + 'transport' => 'array', + ], + + 'failover' => [ + 'transport' => 'failover', + 'mailers' => [ + 'smtp', + 'log', + ], + ], + + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'ses', + 'postmark', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all emails sent by your application to be sent from + | the same address. Here you may specify a name and address that is + | used globally for all emails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + +]; diff --git a/TA_website/config/queue.php b/TA_website/config/queue.php new file mode 100644 index 0000000..116bd8d --- /dev/null +++ b/TA_website/config/queue.php @@ -0,0 +1,112 @@ + env('QUEUE_CONNECTION', 'database'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Laravel. You're also free to add more. + | + | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'after_commit' => false, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), + 'queue' => env('BEANSTALKD_QUEUE', 'default'), + 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), + 'block_for' => 0, + 'after_commit' => false, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'default'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'after_commit' => false, + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), + 'block_for' => null, + 'after_commit' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'job_batches', + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control how and where failed jobs are stored. Laravel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/TA_website/config/services.php b/TA_website/config/services.php new file mode 100644 index 0000000..27a3617 --- /dev/null +++ b/TA_website/config/services.php @@ -0,0 +1,38 @@ + [ + 'token' => env('POSTMARK_TOKEN'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'resend' => [ + 'key' => env('RESEND_KEY'), + ], + + 'slack' => [ + 'notifications' => [ + 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), + 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), + ], + ], + +]; diff --git a/TA_website/config/session.php b/TA_website/config/session.php new file mode 100644 index 0000000..ba0aa60 --- /dev/null +++ b/TA_website/config/session.php @@ -0,0 +1,217 @@ + env('SESSION_DRIVER', 'database'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to expire immediately when the browser is closed then you may + | indicate that via the expire_on_close configuration option. + | + */ + + 'lifetime' => (int) env('SESSION_LIFETIME', 120), + + 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it's stored. All encryption is performed + | automatically by Laravel and you may use the session like normal. + | + */ + + 'encrypt' => env('SESSION_ENCRYPT', false), + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When utilizing the "file" session driver, the session files are placed + | on disk. The default storage location is defined here; however, you + | are free to provide another location where they should be stored. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => env('SESSION_CONNECTION'), + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table to + | be used to store sessions. Of course, a sensible default is defined + | for you; however, you're welcome to change this to another table. + | + */ + + 'table' => env('SESSION_TABLE', 'sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using one of the framework's cache driven session backends, you may + | define the cache store which should be used to store the session data + | between requests. This must match one of your defined cache stores. + | + | Affects: "apc", "dynamodb", "memcached", "redis" + | + */ + + 'store' => env('SESSION_STORE'), + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the session cookie that is created by + | the framework. Typically, you should not need to change this value + | since doing so does not grant a meaningful security improvement. + | + */ + + 'cookie' => env( + 'SESSION_COOKIE', + Str::slug(env('APP_NAME', 'laravel'), '_').'_session' + ), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application, but you're free to change this when necessary. + | + */ + + 'path' => env('SESSION_PATH', '/'), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | This value determines the domain and subdomains the session cookie is + | available to. By default, the cookie will be available to the root + | domain and all subdomains. Typically, this shouldn't be changed. + | + */ + + 'domain' => env('SESSION_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you when it can't be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE'), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. It's unlikely you should disable this option. + | + */ + + 'http_only' => env('SESSION_HTTP_ONLY', true), + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | will set this value to "lax" to permit secure cross-site requests. + | + | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value + | + | Supported: "lax", "strict", "none", null + | + */ + + 'same_site' => env('SESSION_SAME_SITE', 'lax'), + + /* + |-------------------------------------------------------------------------- + | Partitioned Cookies + |-------------------------------------------------------------------------- + | + | Setting this value to true will tie the cookie to the top-level site for + | a cross-site context. Partitioned cookies are accepted by the browser + | when flagged "secure" and the Same-Site attribute is set to "none". + | + */ + + 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), + +]; diff --git a/TA_website/database/.gitignore b/TA_website/database/.gitignore new file mode 100644 index 0000000..9b19b93 --- /dev/null +++ b/TA_website/database/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/TA_website/database/factories/UserFactory.php b/TA_website/database/factories/UserFactory.php new file mode 100644 index 0000000..584104c --- /dev/null +++ b/TA_website/database/factories/UserFactory.php @@ -0,0 +1,44 @@ + + */ +class UserFactory extends Factory +{ + /** + * The current password being used by the factory. + */ + protected static ?string $password; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'name' => fake()->name(), + 'email' => fake()->unique()->safeEmail(), + 'email_verified_at' => now(), + 'password' => static::$password ??= Hash::make('password'), + 'remember_token' => Str::random(10), + ]; + } + + /** + * Indicate that the model's email address should be unverified. + */ + public function unverified(): static + { + return $this->state(fn (array $attributes) => [ + 'email_verified_at' => null, + ]); + } +} diff --git a/TA_website/database/migrations/0001_01_01_000000_create_users_table.php b/TA_website/database/migrations/0001_01_01_000000_create_users_table.php new file mode 100644 index 0000000..05fb5d9 --- /dev/null +++ b/TA_website/database/migrations/0001_01_01_000000_create_users_table.php @@ -0,0 +1,49 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->rememberToken(); + $table->timestamps(); + }); + + Schema::create('password_reset_tokens', function (Blueprint $table) { + $table->string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + + Schema::create('sessions', function (Blueprint $table) { + $table->string('id')->primary(); + $table->foreignId('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + Schema::dropIfExists('password_reset_tokens'); + Schema::dropIfExists('sessions'); + } +}; diff --git a/TA_website/database/migrations/0001_01_01_000001_create_cache_table.php b/TA_website/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..b9c106b --- /dev/null +++ b/TA_website/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration'); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/TA_website/database/migrations/0001_01_01_000002_create_jobs_table.php b/TA_website/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..425e705 --- /dev/null +++ b/TA_website/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,57 @@ +id(); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + + Schema::create('job_batches', function (Blueprint $table) { + $table->string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->longText('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->string('uuid')->unique(); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->longText('exception'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + Schema::dropIfExists('job_batches'); + Schema::dropIfExists('failed_jobs'); + } +}; diff --git a/TA_website/database/migrations/2025_05_07_000000_add_role_column_to_users_table.php b/TA_website/database/migrations/2025_05_07_000000_add_role_column_to_users_table.php new file mode 100644 index 0000000..aaeb7c0 --- /dev/null +++ b/TA_website/database/migrations/2025_05_07_000000_add_role_column_to_users_table.php @@ -0,0 +1,44 @@ +string('role')->nullable()->after('password'); + $table->string('phone_number')->nullable()->after('role'); + $table->text('address')->nullable()->after('phone_number'); + $table->decimal('latitude', 10, 7)->nullable()->after('address'); + $table->decimal('longitude', 10, 7)->nullable()->after('latitude'); + $table->text('shop_description')->nullable()->after('longitude'); + $table->string('profile_photo')->nullable()->after('shop_description'); + $table->timestamp('last_login_at')->nullable()->after('profile_photo'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn([ + 'role', + 'phone_number', + 'address', + 'latitude', + 'longitude', + 'shop_description', + 'profile_photo', + 'last_login_at', + ]); + }); + } +}; \ No newline at end of file diff --git a/TA_website/database/schema/mysql-schema.sql b/TA_website/database/schema/mysql-schema.sql new file mode 100644 index 0000000..6a1ea49 --- /dev/null +++ b/TA_website/database/schema/mysql-schema.sql @@ -0,0 +1,136 @@ +/*M!999999\- enable the sandbox mode */ +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `cache`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `cache` ( + `key` varchar(255) NOT NULL, + `value` mediumtext NOT NULL, + `expiration` int(11) NOT NULL, + PRIMARY KEY (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `cache_locks`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `cache_locks` ( + `key` varchar(255) NOT NULL, + `owner` varchar(255) NOT NULL, + `expiration` int(11) NOT NULL, + PRIMARY KEY (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `failed_jobs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `failed_jobs` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) NOT NULL, + `connection` text NOT NULL, + `queue` text NOT NULL, + `payload` longtext NOT NULL, + `exception` longtext NOT NULL, + `failed_at` timestamp NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`), + UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `job_batches`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `job_batches` ( + `id` varchar(255) NOT NULL, + `name` varchar(255) NOT NULL, + `total_jobs` int(11) NOT NULL, + `pending_jobs` int(11) NOT NULL, + `failed_jobs` int(11) NOT NULL, + `failed_job_ids` longtext NOT NULL, + `options` mediumtext DEFAULT NULL, + `cancelled_at` int(11) DEFAULT NULL, + `created_at` int(11) NOT NULL, + `finished_at` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `jobs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `jobs` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `queue` varchar(255) NOT NULL, + `payload` longtext NOT NULL, + `attempts` tinyint(3) unsigned NOT NULL, + `reserved_at` int(10) unsigned DEFAULT NULL, + `available_at` int(10) unsigned NOT NULL, + `created_at` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `jobs_queue_index` (`queue`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `migrations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `migrations` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `migration` varchar(255) NOT NULL, + `batch` int(11) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `password_reset_tokens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `password_reset_tokens` ( + `email` varchar(255) NOT NULL, + `token` varchar(255) NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `sessions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `sessions` ( + `id` varchar(255) NOT NULL, + `user_id` bigint(20) unsigned DEFAULT NULL, + `ip_address` varchar(45) DEFAULT NULL, + `user_agent` text DEFAULT NULL, + `payload` longtext NOT NULL, + `last_activity` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `sessions_user_id_index` (`user_id`), + KEY `sessions_last_activity_index` (`last_activity`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `users` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `email` varchar(255) NOT NULL, + `email_verified_at` timestamp NULL DEFAULT NULL, + `password` varchar(255) NOT NULL, + `remember_token` varchar(100) DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `users_email_unique` (`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +/*M!999999\- enable the sandbox mode */ +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (1,'0001_01_01_000000_create_users_table',1); +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (2,'0001_01_01_000001_create_cache_table',1); +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (3,'0001_01_01_000002_create_jobs_table',1); diff --git a/TA_website/database/seeders/DatabaseSeeder.php b/TA_website/database/seeders/DatabaseSeeder.php new file mode 100644 index 0000000..d01a0ef --- /dev/null +++ b/TA_website/database/seeders/DatabaseSeeder.php @@ -0,0 +1,23 @@ +create(); + + User::factory()->create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + } +} diff --git a/TA_website/package.json b/TA_website/package.json new file mode 100644 index 0000000..4e4ab6f --- /dev/null +++ b/TA_website/package.json @@ -0,0 +1,16 @@ +{ + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.0.0", + "axios": "^1.8.2", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "tailwindcss": "^4.0.0", + "vite": "^6.2.4" + } +} diff --git a/TA_website/phpunit.xml b/TA_website/phpunit.xml new file mode 100644 index 0000000..506b9a3 --- /dev/null +++ b/TA_website/phpunit.xml @@ -0,0 +1,33 @@ + + + + + tests/Unit + + + tests/Feature + + + + + app + + + + + + + + + + + + + + + + diff --git a/TA_website/project_jahit (3).sql b/TA_website/project_jahit (3).sql new file mode 100644 index 0000000..7e6e949 --- /dev/null +++ b/TA_website/project_jahit (3).sql @@ -0,0 +1,699 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost:3306 +-- Generation Time: Apr 08, 2025 at 03:00 PM +-- Server version: 8.0.30 +-- PHP Version: 8.2.27 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `project_jahit` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `bookings` +-- + +CREATE TABLE `bookings` ( + `id` bigint UNSIGNED NOT NULL, + `customer_id` bigint UNSIGNED NOT NULL, + `tailor_id` bigint UNSIGNED NOT NULL, + `appointment_date` date NOT NULL, + `appointment_time` time NOT NULL, + `service_type` enum('Perbaikan','Jahit Baru') COLLATE utf8mb4_unicode_ci NOT NULL, + `category` enum('Atasan','Bawahan','Terusan') COLLATE utf8mb4_unicode_ci NOT NULL, + `design_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `notes` text COLLATE utf8mb4_unicode_ci, + `status` enum('reservasi','diproses','selesai','dibatalkan') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'reservasi', + `total_price` decimal(10,2) DEFAULT NULL, + `payment_status` enum('unpaid','paid') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'unpaid', + `measurements` json DEFAULT NULL, + `repair_details` json DEFAULT NULL, + `repair_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `repair_notes` text COLLATE utf8mb4_unicode_ci, + `completion_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `completion_notes` text COLLATE utf8mb4_unicode_ci, + `accepted_at` timestamp NULL DEFAULT NULL, + `rejected_at` timestamp NULL DEFAULT NULL, + `completed_at` timestamp NULL DEFAULT NULL, + `pickup_date` date DEFAULT NULL, + `rejection_reason` text COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `bookings` +-- + +INSERT INTO `bookings` (`id`, `customer_id`, `tailor_id`, `appointment_date`, `appointment_time`, `service_type`, `category`, `design_photo`, `notes`, `status`, `total_price`, `payment_status`, `measurements`, `repair_details`, `repair_photo`, `repair_notes`, `completion_photo`, `completion_notes`, `accepted_at`, `rejected_at`, `completed_at`, `pickup_date`, `rejection_reason`, `created_at`, `updated_at`) VALUES +(1, 8, 10, '2025-04-10', '09:00:00', 'Perbaikan', 'Terusan', 'design_photos/piUIpUWjYJulxlbvR7wFuIqNxwK4eryenNJNMw5j.png', 'Catatan tambahan', 'reservasi', NULL, 'unpaid', NULL, NULL, NULL, NULL, NULL, NULL, '2025-04-07 00:15:18', NULL, NULL, NULL, NULL, '2025-04-07 03:40:15', '2025-04-07 00:15:18'), +(2, 8, 10, '2025-04-10', '09:00:00', 'Perbaikan', 'Terusan', 'design_photos/1UsgLBgQPeugWpnHJfJ2Lhog8qXvv487wvN2SJ7n.png', 'Catatan tambahan', 'diproses', NULL, 'unpaid', NULL, NULL, NULL, NULL, NULL, NULL, '2025-04-07 00:22:27', NULL, NULL, NULL, NULL, '2025-04-07 07:22:13', '2025-04-07 00:22:27'), +(3, 8, 10, '2025-04-10', '09:00:00', 'Perbaikan', 'Terusan', 'design_photos/B6RsnNEVYsqSfIeub9lGhnwhKttGwPdXQGYu42Eu.jpg', 'Catatan tambahan', 'selesai', NULL, 'paid', NULL, NULL, NULL, NULL, 'completion_photos/completion_1744012234_3.png', 'Jahitan sudah selesai sesuai permintaan', '2025-04-07 00:34:38', NULL, '2025-04-07 00:50:34', '2025-04-20', NULL, '2025-04-07 07:23:01', '2025-04-07 01:28:23'), +(4, 8, 10, '2025-04-15', '09:00:00', 'Perbaikan', 'Terusan', 'design_photos/4j1gVHz7Z2Cn5FDcyrORiQAKTH59IUq77xsT7SO6.png', 'CACANG', 'reservasi', NULL, 'unpaid', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-04-08 14:39:03', '2025-04-08 14:39:03'), +(5, 8, 10, '2025-04-15', '09:00:00', 'Perbaikan', 'Terusan', 'design_photos/u6T2cklg77Y72T4u0Xr4SPeqxXItI3vFDOAnYVDv.png', 'CACANG CICING', 'reservasi', NULL, 'unpaid', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2025-04-08 14:42:24', '2025-04-08 14:42:24'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cache` +-- + +CREATE TABLE `cache` ( + `key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `value` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `expiration` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cache_locks` +-- + +CREATE TABLE `cache_locks` ( + `key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `owner` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `expiration` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `customer_specialization` +-- + +CREATE TABLE `customer_specialization` ( + `id` bigint UNSIGNED NOT NULL, + `user_id` bigint UNSIGNED NOT NULL, + `tailor_specialization_id` bigint UNSIGNED NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `customer_specialization` +-- + +INSERT INTO `customer_specialization` (`id`, `user_id`, `tailor_specialization_id`, `created_at`, `updated_at`) VALUES +(1, 1, 1, NULL, NULL), +(2, 1, 5, NULL, NULL), +(3, 1, 8, NULL, NULL), +(4, 2, 1, NULL, NULL), +(5, 2, 2, NULL, NULL), +(6, 2, 3, NULL, NULL), +(7, 3, 1, NULL, NULL), +(8, 3, 2, NULL, NULL), +(9, 3, 3, NULL, NULL), +(10, 4, 1, NULL, NULL), +(11, 4, 2, NULL, NULL), +(12, 4, 3, NULL, NULL), +(13, 5, 1, NULL, NULL), +(14, 5, 2, NULL, NULL), +(15, 5, 3, NULL, NULL), +(16, 6, 1, NULL, NULL), +(17, 6, 2, NULL, NULL), +(18, 6, 7, NULL, NULL), +(19, 6, 10, NULL, NULL), +(20, 8, 1, NULL, NULL), +(21, 8, 2, NULL, NULL), +(22, 8, 3, NULL, NULL), +(23, 9, 1, NULL, NULL), +(24, 9, 2, NULL, NULL), +(25, 9, 8, NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `failed_jobs` +-- + +CREATE TABLE `failed_jobs` ( + `id` bigint UNSIGNED NOT NULL, + `uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `connection` text COLLATE utf8mb4_unicode_ci NOT NULL, + `queue` text COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `jobs` +-- + +CREATE TABLE `jobs` ( + `id` bigint UNSIGNED NOT NULL, + `queue` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `attempts` tinyint UNSIGNED NOT NULL, + `reserved_at` int UNSIGNED DEFAULT NULL, + `available_at` int UNSIGNED NOT NULL, + `created_at` int UNSIGNED NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `job_batches` +-- + +CREATE TABLE `job_batches` ( + `id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `total_jobs` int NOT NULL, + `pending_jobs` int NOT NULL, + `failed_jobs` int NOT NULL, + `failed_job_ids` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `options` mediumtext COLLATE utf8mb4_unicode_ci, + `cancelled_at` int DEFAULT NULL, + `created_at` int NOT NULL, + `finished_at` int DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `migrations` +-- + +CREATE TABLE `migrations` ( + `id` int UNSIGNED NOT NULL, + `migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `batch` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `migrations` +-- + +INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES +(1, '0001_01_01_000001_create_cache_table', 1), +(2, '0001_01_01_000002_create_jobs_table', 1), +(3, '2014_10_12_000000_create_users_table', 1), +(4, '2024_03_23_000000_create_tailor_services_table', 1), +(5, '2024_03_23_create_bookings_table', 1), +(6, '2024_03_23_create_tailor_ratings_table', 1), +(7, '2024_03_23_create_tailor_specializations_table', 1), +(8, '2025_03_23_110103_create_sessions_table', 1), +(9, '2025_03_23_112534_create_personal_access_tokens_table', 1), +(10, '2025_03_25_052708_add_measurements_to_bookings_table', 1), +(11, '2025_03_25_053140_add_measurements_to_bookings_table', 1), +(12, '2025_03_25_061103_create_customer_specialization_table', 1), +(13, '2025_03_25_061144_add_coordinates_to_users_table', 1), +(14, '2025_04_06_171929_add_category_to_tailor_specializations', 1), +(15, '2025_04_06_172929_add_photo_to_tailor_specializations', 2), +(16, '2025_04_06_185502_add_photo_to_tailor_specializations_table', 2), +(17, '2024_03_27_create_tailor_galleries_table', 3), +(18, '2025_04_07_082729_add_pickup_date_to_bookings_table', 4), +(19, '2025_04_07_082735_add_pickup_date_to_bookings_table', 4); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `personal_access_tokens` +-- + +CREATE TABLE `personal_access_tokens` ( + `id` bigint UNSIGNED NOT NULL, + `tokenable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `tokenable_id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `token` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL, + `abilities` text COLLATE utf8mb4_unicode_ci, + `last_used_at` timestamp NULL DEFAULT NULL, + `expires_at` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `personal_access_tokens` +-- + +INSERT INTO `personal_access_tokens` (`id`, `tokenable_type`, `tokenable_id`, `name`, `token`, `abilities`, `last_used_at`, `expires_at`, `created_at`, `updated_at`) VALUES +(1, 'App\\Models\\User', 1, 'auth_token', '71cf9a5c892186dffcd9d2d6229bd4185b2b414d0186f15acfa97e86da96229a', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 10:27:36', '2025-04-06 10:27:36'), +(2, 'App\\Models\\User', 2, 'auth_token', 'd452a40a6ffd2a0b1eca2c4a18a3c6d6e4225b571601ad2b6292d2b00870b3f0', '[\"pelanggan\"]', '2025-04-06 10:37:49', NULL, '2025-04-06 10:37:14', '2025-04-06 10:37:49'), +(3, 'App\\Models\\User', 3, 'auth_token', '884196424ffbd114387522bf0f598f7292a3775a24709ac0268deac827a2c7b1', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 10:57:31', '2025-04-06 10:57:31'), +(4, 'App\\Models\\User', 4, 'auth_token', '0074d4b7a7492285196fedb7093022aa9a4634642af7915a0434a22bc19d9fde', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 11:18:36', '2025-04-06 11:18:36'), +(5, 'App\\Models\\User', 3, 'auth_token', '79808553a129ea466df16e8e3c3ab263fbf292ad0521ca9fccfa535cf6ba1637', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 11:20:53', '2025-04-06 11:20:53'), +(6, 'App\\Models\\User', 4, 'auth_token', '4467414437aba2bd8c6c315475e0ef57e2472518d1fbbef9f640040e39ce320e', '[\"pelanggan\"]', '2025-04-06 11:33:45', NULL, '2025-04-06 11:21:40', '2025-04-06 11:33:45'), +(7, 'App\\Models\\User', 4, 'auth_token', 'e1e8173b5d871b4cf5a967ceb880bc78dac89ecbf7679ea054504ac442c887e8', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 11:22:32', '2025-04-06 11:22:32'), +(8, 'App\\Models\\User', 5, 'auth_token', '89ce9e8f5b6571474e7eb6dd532332c3d0117a0fd5f714ab6babcd7bfa8479f0', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 11:37:24', '2025-04-06 11:37:24'), +(9, 'App\\Models\\User', 4, 'auth_token', '26da3dfb384242098aef13292a85d82fb73173ffe5eea15aded842ffb9e7a827', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 11:38:30', '2025-04-06 11:38:30'), +(10, 'App\\Models\\User', 6, 'auth_token', 'eaf599a431564f9f94e5af7a87786d79ac6d1f2145ad1a62f2fa6edd67328b57', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 11:49:30', '2025-04-06 11:49:30'), +(11, 'App\\Models\\User', 7, 'auth_token', 'cf7b87929aa41b6110c50ca7053952abe30f88b242d79390c3a8519cb25aa9e4', '[\"admin\"]', '2025-04-06 12:02:36', NULL, '2025-04-06 12:00:37', '2025-04-06 12:02:36'), +(12, 'App\\Models\\User', 7, 'auth_token', '81a5029d9f316faa583eb9bab4bb5cb0170e8094bbf5402d0b15b61dd1773e1c', '[\"admin\"]', '2025-04-06 12:12:26', NULL, '2025-04-06 12:05:20', '2025-04-06 12:12:26'), +(13, 'App\\Models\\User', 7, 'auth_token', 'b807faf25db5bd36b6d0d5079ff0b3ad5ad1062396a630ef6701caf4d54acbbb', '[\"admin\"]', NULL, NULL, '2025-04-06 12:20:07', '2025-04-06 12:20:07'), +(14, 'App\\Models\\User', 8, 'auth_token', 'da868737d481632b3fba2dffd5decd6c01f247ef185a9e107dae06f9d1b662a7', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 12:20:53', '2025-04-06 12:20:53'), +(15, 'App\\Models\\User', 9, 'auth_token', '679888d9ebaec82a031e166183b1d9ba0361ed8e883445249fc84f2d1dca4e8d', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 12:30:21', '2025-04-06 12:30:21'), +(16, 'App\\Models\\User', 8, 'auth_token', '42d0c0d064a837cbd7c38cf6fb4c6bb008434585384b58b98b741b0b322f43d7', '[\"pelanggan\"]', '2025-04-06 12:44:13', NULL, '2025-04-06 12:40:49', '2025-04-06 12:44:13'), +(17, 'App\\Models\\User', 10, 'auth_token', '9deafb91e4b039c59088de8e5898a28d227050a57b2a18a97b918ccaa7f5613c', '[\"penjahit\"]', NULL, NULL, '2025-04-06 12:42:38', '2025-04-06 12:42:38'), +(18, 'App\\Models\\User', 9, 'auth_token', '855b20f72ae435d0adc6cdd5b538d994ae9f2922f1e0d020465c159bbcdd5343', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 12:48:35', '2025-04-06 12:48:35'), +(19, 'App\\Models\\User', 8, 'auth_token', 'ec422e87fa36776072c61dd7cdb7546fa07659307f9ba1b860bc1063fa13c13e', '[\"pelanggan\"]', NULL, NULL, '2025-04-06 12:52:50', '2025-04-06 12:52:50'), +(20, 'App\\Models\\User', 8, 'auth_token', '752b0ff10388906d1816a6b472a9a874dee3e2f25c6a168a14d89e2f7c58c61b', '[\"pelanggan\"]', '2025-04-06 13:08:02', NULL, '2025-04-06 12:55:11', '2025-04-06 13:08:02'), +(21, 'App\\Models\\User', 10, 'auth_token', 'debd5082f8fc667a4e1f268daec9aaadac6e0c69b9165101daba2b87f1ae86ed', '[\"penjahit\"]', '2025-04-06 13:25:49', NULL, '2025-04-06 13:05:10', '2025-04-06 13:25:49'), +(22, 'App\\Models\\User', 8, 'auth_token', '61dc200a43c1c5cdfcf36d5d54478b12f8f072f327e43c8532b7b9e5438ed6fc', '[\"pelanggan\"]', '2025-04-06 13:46:27', NULL, '2025-04-06 13:33:21', '2025-04-06 13:46:27'), +(23, 'App\\Models\\User', 8, 'auth_token', 'b95f64ec9295b34c35f4ad64c27ff974d9a705f763adbd0b790a88544e3e1bcb', '[\"pelanggan\"]', '2025-04-06 13:39:37', NULL, '2025-04-06 13:39:36', '2025-04-06 13:39:37'), +(24, 'App\\Models\\User', 8, 'auth_token', '9618a4d4fba634a301b800368728490924aa1b2d525cfe80acf931ce328f44c8', '[\"pelanggan\"]', '2025-04-06 13:45:23', NULL, '2025-04-06 13:45:22', '2025-04-06 13:45:23'), +(25, 'App\\Models\\User', 8, 'auth_token', '26f382e74ab72c84c69b138e6e0c5cd42c1edcb008f3d805ddb5a833d4b52ab6', '[\"pelanggan\"]', '2025-04-06 13:58:10', NULL, '2025-04-06 13:53:59', '2025-04-06 13:58:10'), +(26, 'App\\Models\\User', 8, 'auth_token', 'f99bc0835f573697c90f6ddad62fe671101e7da82079e488edbc66f2e554c5f3', '[\"pelanggan\"]', '2025-04-07 00:57:37', NULL, '2025-04-06 20:28:35', '2025-04-07 00:57:37'), +(27, 'App\\Models\\User', 10, 'auth_token', '5a1e733447f8f6de6af4bac6c9687aeadb850c86eb6b44bb7235c713b16081eb', '[\"penjahit\"]', '2025-04-07 19:23:40', NULL, '2025-04-07 00:14:44', '2025-04-07 19:23:40'), +(28, 'App\\Models\\User', 8, 'auth_token', '185fd9d68eb7ba5515001e8f9860bebce271b25b933eff42d3b35b394322c304', '[\"pelanggan\"]', '2025-04-07 01:59:14', NULL, '2025-04-07 01:06:01', '2025-04-07 01:59:14'), +(29, 'App\\Models\\User', 8, 'auth_token', '234fb8594d37bba0072bb0bd32dacd8f7d5fc7691f9f54566d457c8f7e27612f', '[\"pelanggan\"]', NULL, NULL, '2025-04-07 19:20:32', '2025-04-07 19:20:32'), +(30, 'App\\Models\\User', 4, 'auth_token', '9c7c4eb4bf4e602f60e2371cf52fdf74de6bbb2d1aed504100bb0a627616f80f', '[\"pelanggan\"]', NULL, NULL, '2025-04-07 19:21:14', '2025-04-07 19:21:14'), +(31, 'App\\Models\\User', 8, 'auth_token', 'cd83b83dd5134bb3273fe7029f29007d3f3a55540d4e5326d30cbd36b852a507', '[\"pelanggan\"]', '2025-04-08 07:42:24', NULL, '2025-04-08 07:33:26', '2025-04-08 07:42:24'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sessions` +-- + +CREATE TABLE `sessions` ( + `id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `user_id` bigint UNSIGNED DEFAULT NULL, + `ip_address` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `user_agent` text COLLATE utf8mb4_unicode_ci, + `payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `last_activity` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `sessions` +-- + +INSERT INTO `sessions` (`id`, `user_id`, `ip_address`, `user_agent`, `payload`, `last_activity`) VALUES +('8dQeTEhusbDlDxWiblo4is10sjjHzAJRFKgmQAlu', 7, '127.0.0.1', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', 'YTo0OntzOjY6Il90b2tlbiI7czo0MDoiSHRnaEhCVnJGSVVZeHpaZWczNVdKUDh1cmlORTE0ZTFFRjJsZzU0NyI7czo5OiJfcHJldmlvdXMiO2E6MTp7czozOiJ1cmwiO3M6Mzc6Imh0dHA6Ly8xMjcuMC4wLjE6ODA4OC9hZG1pbi9kYXNoYm9hcmQiO31zOjY6Il9mbGFzaCI7YToyOntzOjM6Im9sZCI7YTowOnt9czozOiJuZXciO2E6MDp7fX1zOjUwOiJsb2dpbl93ZWJfNTliYTM2YWRkYzJiMmY5NDAxNTgwZjAxNGM3ZjU4ZWE0ZTMwOTg5ZCI7aTo3O30=', 1744124205); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_galleries` +-- + +CREATE TABLE `tailor_galleries` ( + `id` bigint UNSIGNED NOT NULL, + `user_id` bigint UNSIGNED NOT NULL, + `photo` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `description` text COLLATE utf8mb4_unicode_ci, + `category` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_galleries` +-- + +INSERT INTO `tailor_galleries` (`id`, `user_id`, `photo`, `title`, `description`, `category`, `created_at`, `updated_at`) VALUES +(1, 10, '/storage/gallery_photos/gallery_1743970859_10.jpeg', 'GAUN PENGANTIN', 'Gaun pengantin', 'Gaun Pengantin', '2025-04-06 13:20:59', '2025-04-06 13:20:59'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_ratings` +-- + +CREATE TABLE `tailor_ratings` ( + `id` bigint UNSIGNED NOT NULL, + `booking_id` bigint UNSIGNED NOT NULL, + `customer_id` bigint UNSIGNED NOT NULL, + `tailor_id` bigint UNSIGNED NOT NULL, + `rating` decimal(2,1) NOT NULL, + `review` text COLLATE utf8mb4_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_ratings` +-- + +INSERT INTO `tailor_ratings` (`id`, `booking_id`, `customer_id`, `tailor_id`, `rating`, `review`, `created_at`, `updated_at`) VALUES +(1, 3, 8, 10, '5.0', 'Pelayanan sangat memuaskan, jahitan rapi dan sesuai pesanan!', '2025-04-07 01:37:12', '2025-04-07 01:37:12'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_services` +-- + +CREATE TABLE `tailor_services` ( + `id` bigint UNSIGNED NOT NULL, + `user_id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `description` text COLLATE utf8mb4_unicode_ci NOT NULL, + `price` decimal(10,2) NOT NULL, + `category` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `estimated_days` int NOT NULL DEFAULT '1', + `is_available` tinyint(1) NOT NULL DEFAULT '1', + `service_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_specializations` +-- + +CREATE TABLE `tailor_specializations` ( + `id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `category` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'Uncategorized', + `icon` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_specializations` +-- + +INSERT INTO `tailor_specializations` (`id`, `name`, `category`, `icon`, `photo`, `created_at`, `updated_at`) VALUES +(1, 'Casual', 'Gaya Busana', NULL, '/storage/specialization_photos/specialization_1743966404_1.jpeg', NULL, '2025-04-06 12:06:44'), +(2, 'Formal', 'Gaya Busana', NULL, '/storage/specialization_photos/specialization_1743966521_2.jpeg', NULL, '2025-04-06 12:08:41'), +(3, 'Tradisional', 'Gaya Busana', NULL, '/storage/specialization_photos/specialization_1743966572_3.jpeg', NULL, '2025-04-06 12:09:32'), +(4, 'Modern', 'Gaya Busana', NULL, '/storage/specialization_photos/specialization_1743966613_4.jpeg', NULL, '2025-04-06 12:10:14'), +(5, 'Jahit Baru', 'Jenis Layanan', NULL, '/storage/specialization_photos/specialization_1743966706_5.jpeg', NULL, '2025-04-06 12:11:46'), +(6, 'Perbaikan', 'Jenis Layanan', NULL, '/storage/specialization_photos/specialization_1743966713_6.jpeg', NULL, '2025-04-06 12:11:53'), +(7, 'Design/Custom', 'Jenis Layanan', NULL, '/storage/specialization_photos/specialization_1743966719_7.jpeg', NULL, '2025-04-06 12:11:59'), +(8, 'Border', 'Hiasan Busana', NULL, '/storage/specialization_photos/specialization_1743966737_8.jpeg', NULL, '2025-04-06 12:12:17'), +(9, 'Payet', 'Hiasan Busana', NULL, '/storage/specialization_photos/specialization_1743966742_9.jpeg', NULL, '2025-04-06 12:12:22'), +(10, 'Sulam', 'Hiasan Busana', NULL, '/storage/specialization_photos/specialization_1743966746_10.jpeg', NULL, '2025-04-06 12:12:26'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tailor_specialization_user` +-- + +CREATE TABLE `tailor_specialization_user` ( + `user_id` bigint UNSIGNED NOT NULL, + `tailor_specialization_id` bigint UNSIGNED NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `tailor_specialization_user` +-- + +INSERT INTO `tailor_specialization_user` (`user_id`, `tailor_specialization_id`) VALUES +(10, 1), +(10, 2), +(10, 5); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +CREATE TABLE `users` ( + `id` bigint UNSIGNED NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `role` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `phone_number` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `address` text COLLATE utf8mb4_unicode_ci, + `latitude` decimal(10,7) DEFAULT NULL, + `longitude` decimal(10,7) DEFAULT NULL, + `shop_description` text COLLATE utf8mb4_unicode_ci, + `profile_photo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `email_verified_at` timestamp NULL DEFAULT NULL, + `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `users` +-- + +INSERT INTO `users` (`id`, `name`, `email`, `password`, `role`, `phone_number`, `address`, `latitude`, `longitude`, `shop_description`, `profile_photo`, `email_verified_at`, `remember_token`, `created_at`, `updated_at`) VALUES +(1, 'Nama Pelanggan', 'alif@gmail.com', '$2y$12$liUj6wPrHcAgq/kyKtSkeO4VNadzQT.Z3ltZ2SFN4b/RZAC6IZ2..', 'pelanggan', '081234567890', 'Alamat lengkap', NULL, NULL, NULL, NULL, NULL, NULL, '2025-04-06 10:27:36', '2025-04-06 10:27:36'), +(2, 'Pelanggan Test', 'pelanggan.test@example.com', '$2y$12$atuG.fzjXDq83bdAMTSlMOoJBVBAC1XGOM12aNt1oozfTQRVccgEq', 'pelanggan', '081234567890', 'Jl. Contoh No. 123, Jakarta', '-6.1754000', '106.8272000', NULL, NULL, NULL, NULL, '2025-04-06 10:37:14', '2025-04-06 10:37:14'), +(3, 'Pelanggan Test', 'pelanggan.testt@example.com', '$2y$12$vqBB1ZezZp.llCTECrDwEOquttfd8VVc3y4BMMx1Mpu1r5cA28B6u', 'pelanggan', '081234567890', 'Jl. Contoh No. 123, Jakarta', '-6.1754000', '106.8272000', NULL, NULL, NULL, NULL, '2025-04-06 10:57:31', '2025-04-06 10:57:31'), +(4, 'kumar', 'kumar@gmail.com', '$2y$12$D4F2uiai2nxlfRuOHycU5OlBgza.4cTGC8fGS0ZyJnrCI34tmqKyu', 'pelanggan', '09987654321', 'AAA', '-6.1754000', '106.8272000', NULL, '/storage/profile_photos/1743964425_4.png', NULL, NULL, '2025-04-06 11:18:36', '2025-04-06 11:33:46'), +(5, 'Pelanggan Test', 'pelanggan.tesssat@example.com', '$2y$12$wxadtyXf7PsmfOmRXses3eLn0KXB0/QrmeoAI9Wifbr1eJpARVa1m', 'pelanggan', '081234567890', 'Jl. Contoh No. 123, Jakarta', '-6.1754000', '106.8272000', NULL, NULL, NULL, NULL, '2025-04-06 11:37:24', '2025-04-06 11:37:24'), +(6, 'kuring', 'kuring@gmail.com', '$2y$12$0wyKtAT6OZIho6UPB0WlSeAFvnN6YoeRuSkmoOixeZz5a2MP3wG7e', 'pelanggan', '12345678', 'asdfg', '-6.1754000', '106.8272000', NULL, NULL, NULL, NULL, '2025-04-06 11:49:30', '2025-04-06 11:49:30'), +(7, 'Admin Jahit', 'admin@jahit.com', '$2y$12$tj2jOcn39wbyYWdE44Vkhe1Ln4.u7Xfb1QdYQ.0oItc1fO/KfIGqW', 'admin', '081234567890', 'Jl. Admin No. 1', NULL, NULL, NULL, NULL, NULL, NULL, '2025-04-06 11:57:44', '2025-04-06 11:57:44'), +(8, 'ALIFA SULAEMAN', 'emailKAKAKA@example.com', '$2y$12$uQ9WXGRdC4uMAzRBDKQlZuE7Z1qU9XUu2iYejdSSFC7QpyQ9ONK9S', 'pelanggan', '081234567890', 'Jalan Baru No. 123, Kota Baru', '-6.2088000', '106.8456000', NULL, NULL, NULL, NULL, '2025-04-06 12:20:53', '2025-04-07 01:59:14'), +(9, 'iiii', 'iii@gmail.com', '$2y$12$Vuc39mqi.26jwCD5ZJJ4QOb2IGpzo8U778/mND6UyAjQj3JWElZqq', 'pelanggan', '12345', '23456', '-6.1754000', '106.8272000', NULL, NULL, NULL, NULL, '2025-04-06 12:30:21', '2025-04-06 12:30:21'), +(10, 'Nama Penjahit', 'penjahit@example.com', '$2y$12$cB1R6Qx8BVMfpclqKSPsx.mwVNeWfGp2o7boyZHxi7Qr.AAN26Dhu', 'penjahit', '081234567890', 'Jl. Contoh No. 123, Kota', NULL, NULL, 'Menerima jahitan untuk berbagai model pakaian dengan pengalaman lebih dari 5 tahun.', '/storage/profile_photos/1743970075_10.jpeg', NULL, NULL, '2025-04-06 12:42:38', '2025-04-06 13:07:56'); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `bookings` +-- +ALTER TABLE `bookings` + ADD PRIMARY KEY (`id`), + ADD KEY `bookings_customer_id_foreign` (`customer_id`), + ADD KEY `bookings_tailor_id_foreign` (`tailor_id`); + +-- +-- Indexes for table `cache` +-- +ALTER TABLE `cache` + ADD PRIMARY KEY (`key`); + +-- +-- Indexes for table `cache_locks` +-- +ALTER TABLE `cache_locks` + ADD PRIMARY KEY (`key`); + +-- +-- Indexes for table `customer_specialization` +-- +ALTER TABLE `customer_specialization` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `customer_specialization_user_id_tailor_specialization_id_unique` (`user_id`,`tailor_specialization_id`), + ADD KEY `customer_specialization_tailor_specialization_id_foreign` (`tailor_specialization_id`); + +-- +-- Indexes for table `failed_jobs` +-- +ALTER TABLE `failed_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`); + +-- +-- Indexes for table `jobs` +-- +ALTER TABLE `jobs` + ADD PRIMARY KEY (`id`), + ADD KEY `jobs_queue_index` (`queue`); + +-- +-- Indexes for table `job_batches` +-- +ALTER TABLE `job_batches` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `migrations` +-- +ALTER TABLE `migrations` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `personal_access_tokens` +-- +ALTER TABLE `personal_access_tokens` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `personal_access_tokens_token_unique` (`token`), + ADD KEY `personal_access_tokens_tokenable_type_tokenable_id_index` (`tokenable_type`,`tokenable_id`); + +-- +-- Indexes for table `sessions` +-- +ALTER TABLE `sessions` + ADD PRIMARY KEY (`id`), + ADD KEY `sessions_user_id_index` (`user_id`), + ADD KEY `sessions_last_activity_index` (`last_activity`); + +-- +-- Indexes for table `tailor_galleries` +-- +ALTER TABLE `tailor_galleries` + ADD PRIMARY KEY (`id`), + ADD KEY `tailor_galleries_user_id_foreign` (`user_id`); + +-- +-- Indexes for table `tailor_ratings` +-- +ALTER TABLE `tailor_ratings` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `tailor_ratings_booking_id_customer_id_unique` (`booking_id`,`customer_id`), + ADD KEY `tailor_ratings_customer_id_foreign` (`customer_id`), + ADD KEY `tailor_ratings_tailor_id_foreign` (`tailor_id`); + +-- +-- Indexes for table `tailor_services` +-- +ALTER TABLE `tailor_services` + ADD PRIMARY KEY (`id`), + ADD KEY `tailor_services_user_id_foreign` (`user_id`); + +-- +-- Indexes for table `tailor_specializations` +-- +ALTER TABLE `tailor_specializations` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `tailor_specialization_user` +-- +ALTER TABLE `tailor_specialization_user` + ADD PRIMARY KEY (`user_id`,`tailor_specialization_id`), + ADD KEY `tailor_specialization_user_tailor_specialization_id_foreign` (`tailor_specialization_id`); + +-- +-- Indexes for table `users` +-- +ALTER TABLE `users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `users_email_unique` (`email`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `bookings` +-- +ALTER TABLE `bookings` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6; + +-- +-- AUTO_INCREMENT for table `customer_specialization` +-- +ALTER TABLE `customer_specialization` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=26; + +-- +-- AUTO_INCREMENT for table `failed_jobs` +-- +ALTER TABLE `failed_jobs` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `jobs` +-- +ALTER TABLE `jobs` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `migrations` +-- +ALTER TABLE `migrations` + MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=20; + +-- +-- AUTO_INCREMENT for table `personal_access_tokens` +-- +ALTER TABLE `personal_access_tokens` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=32; + +-- +-- AUTO_INCREMENT for table `tailor_galleries` +-- +ALTER TABLE `tailor_galleries` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; + +-- +-- AUTO_INCREMENT for table `tailor_ratings` +-- +ALTER TABLE `tailor_ratings` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; + +-- +-- AUTO_INCREMENT for table `tailor_services` +-- +ALTER TABLE `tailor_services` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `tailor_specializations` +-- +ALTER TABLE `tailor_specializations` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; + +-- +-- AUTO_INCREMENT for table `users` +-- +ALTER TABLE `users` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `bookings` +-- +ALTER TABLE `bookings` + ADD CONSTRAINT `bookings_customer_id_foreign` FOREIGN KEY (`customer_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `bookings_tailor_id_foreign` FOREIGN KEY (`tailor_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `customer_specialization` +-- +ALTER TABLE `customer_specialization` + ADD CONSTRAINT `customer_specialization_tailor_specialization_id_foreign` FOREIGN KEY (`tailor_specialization_id`) REFERENCES `tailor_specializations` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `customer_specialization_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `tailor_galleries` +-- +ALTER TABLE `tailor_galleries` + ADD CONSTRAINT `tailor_galleries_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `tailor_ratings` +-- +ALTER TABLE `tailor_ratings` + ADD CONSTRAINT `tailor_ratings_booking_id_foreign` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `tailor_ratings_customer_id_foreign` FOREIGN KEY (`customer_id`) REFERENCES `users` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `tailor_ratings_tailor_id_foreign` FOREIGN KEY (`tailor_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `tailor_services` +-- +ALTER TABLE `tailor_services` + ADD CONSTRAINT `tailor_services_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; + +-- +-- Constraints for table `tailor_specialization_user` +-- +ALTER TABLE `tailor_specialization_user` + ADD CONSTRAINT `tailor_specialization_user_tailor_specialization_id_foreign` FOREIGN KEY (`tailor_specialization_id`) REFERENCES `tailor_specializations` (`id`) ON DELETE CASCADE, + ADD CONSTRAINT `tailor_specialization_user_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/TA_website/public/.htaccess b/TA_website/public/.htaccess new file mode 100644 index 0000000..b574a59 --- /dev/null +++ b/TA_website/public/.htaccess @@ -0,0 +1,25 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Handle X-XSRF-Token Header + RewriteCond %{HTTP:x-xsrf-token} . + RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/TA_website/public/favicon.ico b/TA_website/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/TA_website/public/image/LogoGelap.png b/TA_website/public/image/LogoGelap.png new file mode 100644 index 0000000000000000000000000000000000000000..1cdc6cb219e15d5eb64ac4d759c9f3e62e94bdc0 GIT binary patch literal 5999 zcmcgwhdUeI*GH=@s_mDeR@K&$Xw_Cxn<7@th*2|QMQRJJqOBUOSsG%iU3*5*uU#v) z5H(XXtq~>0>-WBY!~47Ux%0WtIrq8e-g7^n^WF%o&CJNfNJB%ztgEA8LPJBFcF{k( zcIBd`Z0LwzGz>mER!ABeCf5HHTAB>>or_6Yq=~i~O~nw;`o-X~tEz!24NX-7(}@E; z4GqU-T@BUefwbH6AwD*%K|Oy+sA1ceHBOG=ZTAMMg$J~5sV(O-FcdI0A*y(FmhufA zClOQ(@Ve`@eHXc4TgV{ECBt8;Y2lev4kxQlJO5Kg#4CpT_V;cv>B-j9(8{(Esw+sX zhL{>z`&fY0Y)Wk+4wHV6HLvXIz1xP{Ya=U=#py2g^+KHU ztz+fyyXCfiwbq%wy8pB>dnFZ9Ls=5~Wd?@!*t`4|RpxEjPI{aGhc$U*9ggM-f(U#2 zsoaPCm)$*~%94mPJB@w(Juht1H+=EdhkWv5C^P^BXcyX}Oa3gfC{sV>TgM6&f8(2q zew~pqyT{+(CW+WtjB)ab)6b4#vask{A_}sA65DDyPCp`#Ss{1h>)Z`OLPE4&>1s7* z=Ubascv+AZGJvHr!z(p2DjZfRZ2F&1Bw#PWMCX(O5{?uE&MVdQORF;|Bi4!ANwy0K z+8CLr&Tp0(!SB!cn22vkdccCZJUSx#E?Z@nl*Z!>H3|PxkA|9#P7&i`|F_)X;c@h~ z=0X~#}8IAgQ({!Ii!-cX(OyYWn)fFa<3#Nt&!3@Vc*Db`0-w+zw%boXd|0WJ*w z>sLS3Dvup56{^>sCyb6h68ijbXh5MT@M{;#*~i8ak^hy?a#MM{MZjXQVq$vXMb|uE z!J!pK??b|h`{rDsmB$MJsOvOtQaZ>o;>SPsiT?n_tRaMEv{rg)Sx_Mqe4Y#sVpP{IhO_^Qxby zv#k{Gv$-+Ij?VD3MMq3zOU9PRo(vaLDR}?PR z*e}y2e*^S2SB5V6k(Q>`Xok7%>}?n&q<$Kdx{Yph9go_KURr?$w2J{phD7T%_!ulpsoDgY0*1>0bfS#}u!P^`?gN=VZr8E14GXu43Ly zdgMy=PIHA`IGB06mTEvpl?T1I;hTTF#FTwFVEzks>wy?+no z;NU^}bP0nc;P{ccgXd$X@UNadl5 zzj0jjk5EyB=kGRtW|qoXdrvbNAYx*&sH!)p*k6@oWjUU|9bi5YhH&Kz+z%=Z zdE∾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 NOji@EQK4oZ@jpOzQ9%Fz literal 0 HcmV?d00001 diff --git a/TA_website/public/image/LogoPutih.png b/TA_website/public/image/LogoPutih.png new file mode 100644 index 0000000000000000000000000000000000000000..f98b82c446b77130f177bfa14a4153b3d7724686 GIT binary patch literal 6166 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 KSby{G)Bgi@dbO$m literal 0 HcmV?d00001 diff --git a/TA_website/public/index.php b/TA_website/public/index.php new file mode 100644 index 0000000..ee8f07e --- /dev/null +++ b/TA_website/public/index.php @@ -0,0 +1,20 @@ +handleRequest(Request::capture()); diff --git a/TA_website/public/robots.txt b/TA_website/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/TA_website/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/TA_website/resources/css/app.css b/TA_website/resources/css/app.css new file mode 100644 index 0000000..3e6abea --- /dev/null +++ b/TA_website/resources/css/app.css @@ -0,0 +1,11 @@ +@import 'tailwindcss'; + +@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; +@source '../../storage/framework/views/*.php'; +@source '../**/*.blade.php'; +@source '../**/*.js'; + +@theme { + --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol', 'Noto Color Emoji'; +} diff --git a/TA_website/resources/js/api.js b/TA_website/resources/js/api.js new file mode 100644 index 0000000..2ebfa5f --- /dev/null +++ b/TA_website/resources/js/api.js @@ -0,0 +1,98 @@ +/** + * API Helper + */ +import { api } from './config'; +import axios from 'axios'; + +/** + * Create API instance + */ +const apiClient = axios.create({ + baseURL: api.baseURL, + timeout: api.timeout, + headers: { + ...api.headers + } +}); + +/** + * Helper for URL path + * @param {string} path + * @returns {string} + */ +export const url = (path = '') => { + // Remove leading slash if present + path = path.replace(/^\/+/, ''); + return path ? `${api.baseURL}/${path}` : api.baseURL; +}; + +/** + * Helper for asset URL (for images, etc) + * @param {string} path + * @returns {string} + */ +export const asset = (path = '') => { + // Remove leading slash if present + path = path.replace(/^\/+/, ''); + const baseURL = api.baseURL.replace('/api', ''); + return path ? `${baseURL}/${path}` : baseURL; +}; + +/** + * API methods + */ +export default { + /** + * Get request + * @param {string} path + * @param {object} params + * @returns {Promise} + */ + get(path, params = {}) { + return apiClient.get(path, { params }); + }, + + /** + * Post request + * @param {string} path + * @param {object} data + * @returns {Promise} + */ + post(path, data = {}) { + return apiClient.post(path, data); + }, + + /** + * Put request + * @param {string} path + * @param {object} data + * @returns {Promise} + */ + put(path, data = {}) { + return apiClient.put(path, data); + }, + + /** + * Delete request + * @param {string} path + * @param {object} params + * @returns {Promise} + */ + delete(path, params = {}) { + return apiClient.delete(path, { params }); + }, + + /** + * Get full URL + * @param {string} path + * @returns {string} + */ + url: url, + + /** + * Get asset URL + * @param {string} path + * @returns {string} + */ + asset: asset +}; \ No newline at end of file diff --git a/TA_website/resources/js/app.js b/TA_website/resources/js/app.js new file mode 100644 index 0000000..e59d6a0 --- /dev/null +++ b/TA_website/resources/js/app.js @@ -0,0 +1 @@ +import './bootstrap'; diff --git a/TA_website/resources/js/bootstrap.js b/TA_website/resources/js/bootstrap.js new file mode 100644 index 0000000..ac5fa12 --- /dev/null +++ b/TA_website/resources/js/bootstrap.js @@ -0,0 +1,15 @@ +import axios from 'axios'; +import { api } from './config'; +import apiHelper from './api'; +import './utils'; // Impor utilities + +window.axios = axios; +window.api = apiHelper; // Export API helper globaly + +window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; +window.axios.defaults.baseURL = api.baseURL; +window.axios.defaults.timeout = api.timeout; +window.axios.defaults.headers = { + ...window.axios.defaults.headers, + ...api.headers +}; diff --git a/TA_website/resources/js/config.js b/TA_website/resources/js/config.js new file mode 100644 index 0000000..bcae2e9 --- /dev/null +++ b/TA_website/resources/js/config.js @@ -0,0 +1,23 @@ +/** + * Base URL configuration + * + * Note: These values are loaded from the server when the page loads. + * See the + + + + + + + diff --git a/TA_website/resources/views/admin/bank-accounts/detail.blade.php b/TA_website/resources/views/admin/bank-accounts/detail.blade.php new file mode 100644 index 0000000..b09914a --- /dev/null +++ b/TA_website/resources/views/admin/bank-accounts/detail.blade.php @@ -0,0 +1,147 @@ +@extends('admin.layouts.app') + +@section('title', 'Detail Akun Bank | TailorHub Admin') + +@section('content') +
+
+

+ Detail Akun Bank +

+ + Kembali + +
+ + + @if (session('success')) + + @endif + + @if (session('error')) + + @endif + + +
+
+

Informasi Akun Bank

+
+
+
+
+

Data Penjahit

+
+

Nama: {{ $bankAccount['user']['name'] }}

+

Email: {{ $bankAccount['user']['email'] }}

+

No. Telepon: {{ $bankAccount['user']['phone_number'] ?? '-' }}

+
+
+
+

Data Rekening

+
+

Nama Bank: {{ $bankAccount['bank_name'] }}

+

Nomor Rekening: {{ $bankAccount['account_number'] }}

+

Nama Pemilik: {{ $bankAccount['account_holder_name'] }}

+

+ Status: + @if ($bankAccount['status'] == 'active') + Diterima + @elseif ($bankAccount['status'] == 'rejected') + Ditolak + @else + {{ $bankAccount['status'] }} + @endif +

+ @if ($bankAccount['status'] == 'rejected' && $bankAccount['rejection_reason']) +

Alasan Penolakan: {{ $bankAccount['rejection_reason'] }}

+ @endif +

Tanggal Verifikasi: {{ \Carbon\Carbon::parse($bankAccount['verified_at'])->format('d M Y H:i') }}

+
+
+
+
+
+ + +
+
+

Riwayat Penarikan

+
+
+ + + + + + + + + + + + + @forelse ($bankAccount['withdrawals'] ?? [] as $withdrawal) + + + + + + + + + @empty + + + + @endforelse + +
IDJumlahStatusBukti PembayaranTanggal DiprosesTanggal Dibuat
+ {{ $withdrawal['id'] }} + + Rp {{ number_format($withdrawal['amount'], 0, ',', '.') }} + + @if ($withdrawal['status'] == 'pending') + + Menunggu + + @elseif ($withdrawal['status'] == 'processing') + + Diproses + + @elseif ($withdrawal['status'] == 'completed') + + Selesai + + @elseif ($withdrawal['status'] == 'rejected') + + Ditolak + + @else + + {{ $withdrawal['status'] }} + + @endif + + @if ($withdrawal['proof_of_payment']) + + Lihat Bukti + + @else + - + @endif + + {{ $withdrawal['processed_at'] ? \Carbon\Carbon::parse($withdrawal['processed_at'])->format('d M Y H:i') : '-' }} + + {{ \Carbon\Carbon::parse($withdrawal['created_at'])->format('d M Y H:i') }} +
+ Tidak ada riwayat penarikan untuk akun bank ini. +
+
+
+
+@endsection \ No newline at end of file diff --git a/TA_website/resources/views/admin/bank-accounts/pending.blade.php b/TA_website/resources/views/admin/bank-accounts/pending.blade.php new file mode 100644 index 0000000..9c563dd --- /dev/null +++ b/TA_website/resources/views/admin/bank-accounts/pending.blade.php @@ -0,0 +1,76 @@ +@extends('admin.layouts.app') + +@section('title', 'Verifikasi Akun Bank') + +@section('content') +
+
+

Daftar Akun Bank Menunggu Verifikasi

+ + @if (session('success')) + + @endif + + @if (session('error')) + + @endif + + @if(empty($bankAccounts)) +
+ + + +

Tidak ada akun bank yang menunggu verifikasi

+

Semua akun bank sudah diverifikasi.

+
+ @else +
+ + + + + + + + + + + + + + + @foreach($bankAccounts as $bankAccount) + + + + + + + + + + + @endforeach + +
IDNama PenjahitBankNo. RekeningAtas NamaStatusTanggalAksi
{{ $bankAccount['id'] }}{{ $bankAccount['user']['name'] }}{{ $bankAccount['bank_name'] }}{{ $bankAccount['account_number'] }}{{ $bankAccount['account_holder_name'] }} + + {{ ucfirst($bankAccount['status']) }} + + {{ \Carbon\Carbon::parse($bankAccount['created_at'])->format('d M Y') }} + @if($bankAccount['status'] == 'pending') + Verifikasi + @endif +
+
+ @endif +
+
+@endsection \ No newline at end of file diff --git a/TA_website/resources/views/admin/bank-accounts/verified.blade.php b/TA_website/resources/views/admin/bank-accounts/verified.blade.php new file mode 100644 index 0000000..32dedff --- /dev/null +++ b/TA_website/resources/views/admin/bank-accounts/verified.blade.php @@ -0,0 +1,118 @@ +@extends('admin.layouts.app') + +@section('title', 'Akun Bank Terverifikasi | TailorHub Admin') + +@section('content') +
+

+ Akun Bank Terverifikasi +

+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ + + @if (session('success')) + + @endif + + @if (session('error')) + + @endif + + +
+ + + + + + + + + + + + + + + @forelse ($bankAccounts as $account) + + + + + + + + + + + @empty + + + + @endforelse + +
IDPenjahitBankNomor RekeningNama PemilikStatusWaktu VerifikasiAksi
+ {{ $account['id'] }} + +
+
+

{{ $account['user']['name'] }}

+

{{ $account['user']['email'] }}

+
+
+
+ {{ $account['bank_name'] }} + + {{ $account['account_number'] }} + + {{ $account['account_holder_name'] }} + + @if ($account['status'] == 'active') + + Diterima + + @elseif ($account['status'] == 'rejected') + + Ditolak + + @else + + {{ $account['status'] }} + + @endif + + {{ \Carbon\Carbon::parse($account['verified_at'])->format('d M Y H:i') }} + + Detail +
+ Tidak ada data akun bank yang terverifikasi. +
+
+
+@endsection \ No newline at end of file diff --git a/TA_website/resources/views/admin/bank-accounts/verify.blade.php b/TA_website/resources/views/admin/bank-accounts/verify.blade.php new file mode 100644 index 0000000..e522075 --- /dev/null +++ b/TA_website/resources/views/admin/bank-accounts/verify.blade.php @@ -0,0 +1,105 @@ +@extends('admin.layouts.app') + +@section('title', 'Verifikasi Akun Bank') + +@section('content') +
+
+
+

Verifikasi Akun Bank #{{ $bankAccount['id'] }}

+ + Kembali + +
+ + @if (session('error')) + + @endif + + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+

Detail Akun Bank

+
+
+

Nama Penjahit:

+

{{ $bankAccount['user']['name'] }}

+
+
+

Email:

+

{{ $bankAccount['user']['email'] }}

+
+
+

Bank:

+

{{ $bankAccount['bank_name'] }}

+
+
+

Nomor Rekening:

+

{{ $bankAccount['account_number'] }}

+
+
+

Atas Nama:

+

{{ $bankAccount['account_holder_name'] }}

+
+
+

Tanggal Pendaftaran:

+

{{ \Carbon\Carbon::parse($bankAccount['created_at'])->format('d M Y H:i') }}

+
+
+
+ +
+ @csrf + +
+ + +
+ + + +
+ +
+
+
+
+ +@push('scripts') + +@endpush +@endsection \ No newline at end of file diff --git a/TA_website/resources/views/admin/bookings/index.blade.php b/TA_website/resources/views/admin/bookings/index.blade.php new file mode 100644 index 0000000..1539b44 --- /dev/null +++ b/TA_website/resources/views/admin/bookings/index.blade.php @@ -0,0 +1,363 @@ +@extends('admin.layouts.app') + +@section('title', 'Pesanan') + +@section('content') +
+ +
+

Daftar Pesanan

+ + +
+ +
+ + + + +
+ + +
+ + +
+
+ + +
+
+
+
+
+ + +
+
+
+ + + + + + + + + + + + + + + + +
IDPelangganPenjahitTanggalLayananStatusPembayaranAksi
+
+
+
+ + +
+
+
+ +
+
+
+

Detail Pesanan #

+

Dibuat pada

+
+ +
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+

Informasi Pelanggan

+
+
+
+
+

Nama

+

+
+
+

Telepon

+

+
+
+

Alamat

+

+
+
+
+
+ + +
+
+

Detail Pesanan

+
+
+
+
+

Jenis Layanan

+

+
+
+

Kategori

+

+
+
+

Tanggal Appointment

+

+
+
+

Jam

+

+
+
+

Catatan

+

+
+
+
+
+ + +
+
+

Foto Design

+
+
+ Design Photo +
+
+ + + +
+
+
+
+
+@endsection + +@push('scripts') + +@endpush diff --git a/TA_website/resources/views/admin/customers/index.blade.php b/TA_website/resources/views/admin/customers/index.blade.php new file mode 100644 index 0000000..c68b98f --- /dev/null +++ b/TA_website/resources/views/admin/customers/index.blade.php @@ -0,0 +1,1132 @@ +@extends('admin.layouts.app') + +@section('title', 'Pelanggan') + +@section('content') +
+
+

Daftar Pelanggan

+ +
+ + + + + + + + + + + + +
+ +
+
+
+
+ +
+ + + +
+
+
+
+
+ + +
+
+
+
+ +
+ + + + + + + + + + + + + + + +
+ Nama + + Email + + Telepon + + Alamat + + Spesialisasi + + Pesanan + + Aksi +
+
+ + +
+
+ + +
+ +
+
+
+ +@push('scripts') + + +@endpush +@endsection \ No newline at end of file diff --git a/TA_website/resources/views/admin/dashboard.blade.php b/TA_website/resources/views/admin/dashboard.blade.php new file mode 100644 index 0000000..cc4b0e7 --- /dev/null +++ b/TA_website/resources/views/admin/dashboard.blade.php @@ -0,0 +1,314 @@ +@extends('admin.layouts.app') + +@section('title', 'Dashboard') + +@section('content') +
+ + + + +
+
+
+
+ + + +
+
+

Total Penjahit

+

-

+
+
+
+ +
+
+
+ + + +
+
+

Total Pelanggan

+

-

+
+
+
+ +
+
+
+ + + +
+
+

Total Pesanan

+

-

+
+
+
+ + {{--
+
+
+ + + +
+
+

Total Layanan

+

-

+
+
+
+ +
+
+
+ + + +
+
+

Rating Rata-rata

+

-

+
+
+
--}} +
+ + +
+
+

Status Pesanan

+
+ +
+
+ +
+

Statistik Bulan Ini

+
+
+
+
+ Total Pesanan +
+ - +
+
+
+
+ Pesanan Selesai +
+ - +
+
+
+
+ Tingkat Penyelesaian +
+ - +
+
+
+
+ + +
+
+
+

Pesanan Terbaru

+
+ + + + + + + + + + + + + +
IDPelangganPenjahitStatusTanggal
+
+
+
+ +
+
+

Penjahit Teratas

+
+ +
+
+
+
+ + +
+
+

Pengguna Terbaru

+
+ + + + + + + + + + + + +
IDNamaRoleTanggal Daftar
+
+
+
+
+ + + + + +@endsection diff --git a/TA_website/resources/views/admin/js/config.blade.php b/TA_website/resources/views/admin/js/config.blade.php new file mode 100644 index 0000000..5b08c54 --- /dev/null +++ b/TA_website/resources/views/admin/js/config.blade.php @@ -0,0 +1,16 @@ +/** + * Base URL configuration + */ +export const baseURL = '{{ rtrim(config('api.url'), '/') }}'; + +/** + * API configuration + */ +export const api = { + baseURL: baseURL + '/api', + timeout: {{ config('api.timeout', 30) * 1000 }}, + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + } +}; \ No newline at end of file diff --git a/TA_website/resources/views/admin/layouts/admin.blade.php b/TA_website/resources/views/admin/layouts/admin.blade.php new file mode 100644 index 0000000..3373c62 --- /dev/null +++ b/TA_website/resources/views/admin/layouts/admin.blade.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/TA_website/resources/views/admin/layouts/app.blade.php b/TA_website/resources/views/admin/layouts/app.blade.php new file mode 100644 index 0000000..8b52555 --- /dev/null +++ b/TA_website/resources/views/admin/layouts/app.blade.php @@ -0,0 +1,85 @@ + + + + + + @yield('title') - TailorHub Admin + + + + + + + + + +
+ + @include('admin.layouts.sidebar') + + +
+ +
+
+

@yield('title')

+
+
+ +
+ Profil +
+ @csrf + +
+
+
+
+
+
+ + +
+ @yield('content') +
+
+
+ + @stack('scripts') + + + + \ No newline at end of file diff --git a/TA_website/resources/views/admin/layouts/sidebar.blade.php b/TA_website/resources/views/admin/layouts/sidebar.blade.php new file mode 100644 index 0000000..1d49770 --- /dev/null +++ b/TA_website/resources/views/admin/layouts/sidebar.blade.php @@ -0,0 +1,146 @@ +
+ +
+
+ + + + {{-- Logo Putih --}} + TailorHub +
+
+ + +
+
+
+ {{ substr(Auth::user()->name, 0, 1) }} +
+
+

{{ Auth::user()->name }}

+

Administrator

+
+
+
+ + + + + +
+
+ @csrf + +
+
+
diff --git a/TA_website/resources/views/admin/specializations/index.blade.php b/TA_website/resources/views/admin/specializations/index.blade.php new file mode 100644 index 0000000..3f5edb5 --- /dev/null +++ b/TA_website/resources/views/admin/specializations/index.blade.php @@ -0,0 +1,496 @@ +@extends('admin.layouts.app') + +@section('title', 'Spesialisasi') + +@section('content') +
+ +
+

Daftar Spesialisasi

+ + +
+
+ + + + +
+ + +
+
+ + +
+ +
+
+ + + + + + + +@endsection + +@push('styles') + +@endpush + +@push('scripts') + + +@endpush diff --git a/TA_website/resources/views/admin/tailors/index.blade.php b/TA_website/resources/views/admin/tailors/index.blade.php new file mode 100644 index 0000000..efd5a4d --- /dev/null +++ b/TA_website/resources/views/admin/tailors/index.blade.php @@ -0,0 +1,977 @@ +@extends('admin.layouts.app') + +@section('title', 'Penjahit') + +@section('content') +
+ +
+

Daftar Penjahit

+ + +
+ +
+ + + + +
+ + +
+ + + +
+
+ + + + +
+ +
+
+
+
+ + +
+
+ + @if(session('error')) + + @endif + + @if(session('success')) + + @endif + + +
+ @forelse($tailors as $tailor) +
+ +
+
+
+ @if(isset($tailor['profile']['photo'])) + {{ $tailor['name'] }} + @else + {{ substr($tailor['name'], 0, 2) }} + @endif +
+
+

{{ $tailor['name'] }}

+
+
+ @for($i = 1; $i <= 5; $i++) + @if($i <= $tailor['ratings']['average_rating']) + + + + @else + + + + @endif + @endfor + ({{ $tailor['ratings']['total_ratings'] }}) +
+
+

{{ $tailor['phone'] }}

+
+
+
+ + +
+

Informasi Toko

+

{{ $tailor['profile']['shop_name'] }}

+

{{ $tailor['profile']['address'] }}

+

{{ $tailor['profile']['description'] }}

+
+ + + @if(count($tailor['specializations']) > 0) +
+

Spesialisasi

+
+ @foreach($tailor['specializations'] as $specialization) + + {{ $specialization['name'] }} + + @endforeach +
+
+ @endif + + + @if(isset($tailor['ratings']['reviews']) && count($tailor['ratings']['reviews']) > 0) +
+

Review Terbaru

+
+

"{!! nl2br(e($tailor['ratings']['reviews'][0]['comment'])) !!}"

+

{{ \Carbon\Carbon::parse($tailor['ratings']['reviews'][0]['created_at'])->diffForHumans() }}

+
+
+ @endif + + +
+ + + +
+
+ @empty +
+

Tidak ada data penjahit

+
+ @endforelse +
+
+ + + + + + + + + + +@endsection + +@push('styles') + +@endpush + +@push('scripts') + + +@endpush \ No newline at end of file diff --git a/TA_website/resources/views/admin/user/admin.blade.php b/TA_website/resources/views/admin/user/admin.blade.php new file mode 100644 index 0000000..908a682 --- /dev/null +++ b/TA_website/resources/views/admin/user/admin.blade.php @@ -0,0 +1,465 @@ +@extends('admin.layouts.app') + +@section('title', 'Profil Admin') + +@section('content') +
+ +
+
+
+ A + +
+ +
+
+

Loading...

+

Loading...

+

+ + + + Administrator +

+ +
+
+ + +
+ +
+

Informasi Kontak

+
+
+

Nomor Telepon

+

Loading...

+
+
+

Alamat

+

Loading...

+
+
+

Terdaftar Sejak

+

Loading...

+
+
+
+ + +
+

Informasi Akun

+
+
+

ID Admin

+

Loading...

+
+
+

Role

+

Loading...

+
+
+

Terakhir Diperbarui

+

Loading...

+
+
+
+
+
+ + + + + + + +@endsection + +@push('styles') + +@endpush + +@push('scripts') + + +@endpush diff --git a/TA_website/resources/views/admin/withdrawals/history.blade.php b/TA_website/resources/views/admin/withdrawals/history.blade.php new file mode 100644 index 0000000..eb6d643 --- /dev/null +++ b/TA_website/resources/views/admin/withdrawals/history.blade.php @@ -0,0 +1,363 @@ +@extends('admin.layouts.app') + +@section('title', 'Riwayat Penarikan Dana') + +@section('content') +
+
+

Riwayat Penarikan Dana

+ + @if (session('success')) + + @endif + + @if (session('error')) + + @endif + +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + Reset + +
+
+
+ + @if(empty($withdrawalHistory['data'])) +
+ + + +

Tidak ada riwayat penarikan

+

Tidak ada data penarikan yang selesai atau ditolak.

+
+ @else +
+ + + + + + + + + + + + + + + + @foreach($withdrawalHistory['data'] as $withdrawal) + + + + + + + + + + + + @endforeach + +
IDNama PenjahitBankNo. RekeningJumlahStatusTgl. DiprosesTgl. DibuatDetail
{{ $withdrawal['id'] }}{{ $withdrawal['wallet']['user']['name'] }}{{ $withdrawal['bank_account']['bank_name'] }}{{ $withdrawal['bank_account']['account_number'] }}Rp {{ number_format($withdrawal['amount'], 0, ',', '.') }} + + @if($withdrawal['status'] == 'completed') Selesai + @elseif($withdrawal['status'] == 'rejected') Ditolak + @else {{ ucfirst($withdrawal['status']) }} + @endif + + {{ \Carbon\Carbon::parse($withdrawal['processed_at'])->format('d M Y H:i') }}{{ \Carbon\Carbon::parse($withdrawal['created_at'])->format('d M Y H:i') }} + +
+
+ + +
+ +
+ @endif +
+
+ + + + +@endsection + +@push('scripts') + +@endpush \ No newline at end of file diff --git a/TA_website/resources/views/admin/withdrawals/pending.blade.php b/TA_website/resources/views/admin/withdrawals/pending.blade.php new file mode 100644 index 0000000..65c117d --- /dev/null +++ b/TA_website/resources/views/admin/withdrawals/pending.blade.php @@ -0,0 +1,76 @@ +@extends('admin.layouts.app') + +@section('title', 'Penarikan Dana Pending') + +@section('content') +
+
+

Daftar Penarikan Dana Pending

+ + @if (session('success')) + + @endif + + @if (session('error')) + + @endif + + @if(empty($withdrawals)) +
+ + + +

Tidak ada penarikan dana pending

+

Semua penarikan dana sudah diproses.

+
+ @else +
+ + + + + + + + + + + + + + + @foreach($withdrawals as $withdrawal) + + + + + + + + + + + @endforeach + +
IDNama PenjahitBankNo. RekeningJumlahStatusTanggalAksi
{{ $withdrawal['id'] }}{{ $withdrawal['wallet']['user']['name'] }}{{ $withdrawal['bank_account']['bank_name'] }}{{ $withdrawal['bank_account']['account_number'] }}Rp {{ number_format($withdrawal['amount'], 0, ',', '.') }} + + {{ ucfirst($withdrawal['status']) }} + + {{ \Carbon\Carbon::parse($withdrawal['created_at'])->format('d M Y') }} + @if($withdrawal['status'] == 'pending') + Proses + @endif +
+
+ @endif +
+
+@endsection \ No newline at end of file diff --git a/TA_website/resources/views/admin/withdrawals/process.blade.php b/TA_website/resources/views/admin/withdrawals/process.blade.php new file mode 100644 index 0000000..88d10e5 --- /dev/null +++ b/TA_website/resources/views/admin/withdrawals/process.blade.php @@ -0,0 +1,120 @@ +@extends('admin.layouts.app') + +@section('title', 'Proses Penarikan Dana') + +@section('content') +
+
+
+

Proses Penarikan Dana #{{ $withdrawal['id'] }}

+ + Kembali + +
+ + @if (session('error')) + + @endif + + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+

Detail Penarikan

+
+
+

Nama Penjahit:

+

{{ $withdrawal['wallet']['user']['name'] }}

+
+
+

Jumlah Penarikan:

+

Rp {{ number_format($withdrawal['amount'], 0, ',', '.') }}

+
+
+

Bank:

+

{{ $withdrawal['bank_account']['bank_name'] }}

+
+
+

Nomor Rekening:

+

{{ $withdrawal['bank_account']['account_number'] }}

+
+
+

Atas Nama:

+

{{ $withdrawal['bank_account']['account_holder_name'] }}

+
+
+

Tanggal Permintaan:

+

{{ \Carbon\Carbon::parse($withdrawal['created_at'])->format('d M Y H:i') }}

+
+
+
+ +
+ @csrf + +
+ + +
+ + + + + +
+ +
+
+
+
+ +@push('scripts') + +@endpush +@endsection \ No newline at end of file diff --git a/TA_website/resources/views/welcome.blade.php b/TA_website/resources/views/welcome.blade.php new file mode 100644 index 0000000..c893b80 --- /dev/null +++ b/TA_website/resources/views/welcome.blade.php @@ -0,0 +1,277 @@ + + + + + + + Laravel + + + + + + + @if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot'))) + @vite(['resources/css/app.css', 'resources/js/app.js']) + @else + + @endif + + +
+ @if (Route::has('login')) + + @endif +
+
+
+
+

Let's get started

+

Laravel has an incredibly rich ecosystem.
We suggest starting with the following.

+ + +
+
+ {{-- Laravel Logo --}} + + + + + + + + + + + {{-- Light Mode 12 SVG --}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{-- Dark Mode 12 SVG --}} + +
+
+
+
+ + @if (Route::has('login')) + + @endif + + diff --git a/TA_website/routes/console.php b/TA_website/routes/console.php new file mode 100644 index 0000000..3c9adf1 --- /dev/null +++ b/TA_website/routes/console.php @@ -0,0 +1,8 @@ +comment(Inspiring::quote()); +})->purpose('Display an inspiring quote'); diff --git a/TA_website/routes/web.php b/TA_website/routes/web.php new file mode 100644 index 0000000..66ac101 --- /dev/null +++ b/TA_website/routes/web.php @@ -0,0 +1,56 @@ +view('admin.js.config') + ->header('Content-Type', 'application/javascript'); +})->name('js.config'); + +Route::get('/', function () { + return redirect()->route('admin.login'); +}); + +// Admin Authentication Routes +Route::get('/admin/login', [AuthController::class, 'showLoginForm'])->name('admin.login'); +Route::post('/admin/login', [AuthController::class, 'login'])->name('admin.login.submit'); +Route::post('/admin/logout', [AuthController::class, 'logout'])->name('admin.logout'); + +// Admin Routes +Route::middleware(['auth', 'admin'])->prefix('admin')->name('admin.')->group(function () { + Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard'); + Route::get('/profile', function () { + return view('admin.user.admin'); + })->name('user.profile'); + Route::resource('customers', CustomerController::class); + Route::resource('tailors', TailorController::class); + Route::get('/bookings', [BookingController::class, 'index'])->name('bookings.index'); + Route::resource('specializations', SpecializationController::class); + + // Penarikan Dana Routes + Route::controller(WithdrawalController::class)->group(function () { + Route::get('/withdrawals/pending', 'pending')->name('withdrawals.pending'); + Route::get('/withdrawals/history', 'history')->name('withdrawals.history'); + Route::get('/withdrawals/{withdrawal}/process', 'showProcess')->name('withdrawals.show-process'); + Route::post('/withdrawals/{withdrawal}/process', 'process')->name('withdrawals.process'); + }); + + // Akun Bank Routes + Route::controller(BankAccountController::class)->group(function () { + Route::get('/bank-accounts/pending', 'pending')->name('bank-accounts.pending'); + Route::get('/bank-accounts/verified', 'verified')->name('bank-accounts.verified'); + Route::get('/bank-accounts/{bankAccount}', 'detail')->name('bank-accounts.detail'); + Route::get('/bank-accounts/{bankAccount}/verify', 'showVerify')->name('bank-accounts.show-verify'); + Route::post('/bank-accounts/{bankAccount}/verify', 'verify')->name('bank-accounts.verify'); + }); +}); diff --git a/TA_website/storage/app/.gitignore b/TA_website/storage/app/.gitignore new file mode 100644 index 0000000..fedb287 --- /dev/null +++ b/TA_website/storage/app/.gitignore @@ -0,0 +1,4 @@ +* +!private/ +!public/ +!.gitignore diff --git a/TA_website/storage/app/private/.gitignore b/TA_website/storage/app/private/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/storage/app/private/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/storage/app/public/.gitignore b/TA_website/storage/app/public/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/storage/framework/.gitignore b/TA_website/storage/framework/.gitignore new file mode 100644 index 0000000..05c4471 --- /dev/null +++ b/TA_website/storage/framework/.gitignore @@ -0,0 +1,9 @@ +compiled.php +config.php +down +events.scanned.php +maintenance.php +routes.php +routes.scanned.php +schedule-* +services.json diff --git a/TA_website/storage/framework/cache/.gitignore b/TA_website/storage/framework/cache/.gitignore new file mode 100644 index 0000000..01e4a6c --- /dev/null +++ b/TA_website/storage/framework/cache/.gitignore @@ -0,0 +1,3 @@ +* +!data/ +!.gitignore diff --git a/TA_website/storage/framework/cache/data/.gitignore b/TA_website/storage/framework/cache/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/storage/framework/cache/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/storage/framework/sessions/.gitignore b/TA_website/storage/framework/sessions/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/storage/framework/testing/.gitignore b/TA_website/storage/framework/testing/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/storage/framework/testing/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/storage/framework/views/.gitignore b/TA_website/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/storage/logs/.gitignore b/TA_website/storage/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/TA_website/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/TA_website/tests/Feature/ExampleTest.php b/TA_website/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..8364a84 --- /dev/null +++ b/TA_website/tests/Feature/ExampleTest.php @@ -0,0 +1,19 @@ +get('/'); + + $response->assertStatus(200); + } +} diff --git a/TA_website/tests/TestCase.php b/TA_website/tests/TestCase.php new file mode 100644 index 0000000..fe1ffc2 --- /dev/null +++ b/TA_website/tests/TestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } +} diff --git a/TA_website/vite.config.js b/TA_website/vite.config.js new file mode 100644 index 0000000..29fbfe9 --- /dev/null +++ b/TA_website/vite.config.js @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [ + laravel({ + input: ['resources/css/app.css', 'resources/js/app.js'], + refresh: true, + }), + tailwindcss(), + ], +});

Laravel Logo

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 M(aoW9yZ_lg0i62NzyJUM literal 0 HcmV?d00001 diff --git a/TA_android/assets/images/payment/bca.png b/TA_android/assets/images/payment/bca.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7be79c3457009c8d5cd191eacbbc974e8ab8dd GIT binary patch literal 95653 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