From 1dc1b37409228b8493997751a7e4fe87b299f0e4 Mon Sep 17 00:00:00 2001 From: thisdell Date: Wed, 29 Jul 2026 10:56:06 +0700 Subject: [PATCH] Initial commit: Sistem Informasi Klinik Sahabat Keluarga --- sk-klinik.my.id/.editorconfig | 18 + sk-klinik.my.id/.env.example | 65 + sk-klinik.my.id/.gitattributes | 11 + sk-klinik.my.id/.github/workflows/lint.yml | 50 + sk-klinik.my.id/.github/workflows/tests.yml | 60 + sk-klinik.my.id/.gitignore | 23 + sk-klinik.my.id/.htaccess | 7 + .../app/Actions/Fortify/CreateNewUser.php | 33 + .../app/Actions/Fortify/ResetUserPassword.php | 29 + .../app/Concerns/PasswordValidationRules.php | 29 + .../app/Concerns/ProfileValidationRules.php | 50 + .../GeneratePatientMedicalRecordNumbers.php | 66 + .../Controllers/Admin/PatientController.php | 38 + .../app/Http/Controllers/Controller.php | 8 + .../Http/Middleware/CheckMaintenanceMode.php | 38 + .../app/Livewire/Actions/Logout.php | 22 + .../app/Livewire/Admin/Categories.php | 77 + .../app/Livewire/Admin/Dashboard.php | 34 + .../app/Livewire/Admin/DoctorManager.php | 146 + .../app/Livewire/Admin/ManageAntrean.php | 411 + sk-klinik.my.id/app/Livewire/Admin/News.php | 54 + .../app/Livewire/Admin/NewsCreate.php | 56 + .../app/Livewire/Admin/NewsEdit.php | 77 + .../app/Livewire/Admin/PatientHistory.php | 32 + .../app/Livewire/Admin/PatientManager.php | 243 + .../app/Livewire/Admin/PermissionManager.php | 77 + .../app/Livewire/Admin/RoleManager.php | 76 + .../app/Livewire/Admin/RolePermissions.php | 39 + .../app/Livewire/Admin/ServiceManager.php | 136 + .../app/Livewire/Admin/SiteSettings.php | 136 + .../app/Livewire/Admin/UserManager.php | 108 + .../app/Livewire/Guest/AboutPage.php | 23 + .../app/Livewire/Guest/CompleteProfile.php | 85 + .../app/Livewire/Guest/Dashboard.php | 13 + .../app/Livewire/Guest/DoctorPage.php | 16 + .../app/Livewire/Guest/LandingPage.php | 50 + .../app/Livewire/Guest/NewsIndex.php | 23 + .../app/Livewire/Guest/NewsShow.php | 36 + .../app/Livewire/Patient/BookingAntrean.php | 126 + .../app/Livewire/Patient/CompleteProfile.php | 77 + .../app/Livewire/Patient/Dashboard.php | 36 + sk-klinik.my.id/app/Livewire/Patient/News.php | 36 + .../app/Livewire/Patient/NewsDetail.php | 24 + .../app/Livewire/Patient/PatientProfile.php | 80 + .../app/Livewire/Settings/Appearance.php | 12 + .../app/Livewire/Settings/DeleteUserForm.php | 29 + .../app/Livewire/Settings/Profile.php | 81 + .../app/Livewire/Settings/Security.php | 224 + .../Settings/TwoFactor/RecoveryCodes.php | 50 + sk-klinik.my.id/app/Models/Appointment.php | 88 + sk-klinik.my.id/app/Models/Category.php | 15 + sk-klinik.my.id/app/Models/Doctor.php | 21 + sk-klinik.my.id/app/Models/MedicalRecord.php | 25 + sk-klinik.my.id/app/Models/News.php | 65 + sk-klinik.my.id/app/Models/Patient.php | 63 + sk-klinik.my.id/app/Models/Service.php | 24 + .../app/Models/ServiceCategory.php | 15 + sk-klinik.my.id/app/Models/Setting.php | 38 + sk-klinik.my.id/app/Models/User.php | 83 + .../app/Providers/AppServiceProvider.php | 74 + .../app/Providers/FortifyServiceProvider.php | 82 + .../app/View/Components/GuestLayout.php | 26 + sk-klinik.my.id/artisan | 18 + sk-klinik.my.id/bootstrap/app.php | 24 + sk-klinik.my.id/bootstrap/cache/.gitignore | 2 + sk-klinik.my.id/bootstrap/providers.php | 9 + sk-klinik.my.id/composer.json | 108 + sk-klinik.my.id/composer.lock | 11053 ++++++++++++++++ sk-klinik.my.id/config/app.php | 126 + sk-klinik.my.id/config/auth.php | 117 + sk-klinik.my.id/config/cache.php | 117 + sk-klinik.my.id/config/database.php | 184 + sk-klinik.my.id/config/filesystems.php | 80 + sk-klinik.my.id/config/fortify.php | 157 + sk-klinik.my.id/config/logging.php | 132 + sk-klinik.my.id/config/mail.php | 118 + sk-klinik.my.id/config/permission.php | 202 + sk-klinik.my.id/config/queue.php | 129 + sk-klinik.my.id/config/services.php | 38 + sk-klinik.my.id/config/session.php | 217 + sk-klinik.my.id/config/toaster.php | 61 + sk-klinik.my.id/database - copy | Bin 0 -> 208896 bytes sk-klinik.my.id/database/.gitignore | 1 + .../database/factories/UserFactory.php | 60 + .../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 | 59 + ..._add_two_factor_columns_to_users_table.php | 34 + ..._03_14_031324_create_permission_tables.php | 134 + ...026_03_14_031532_create_settings_table.php | 29 + ...026_03_14_143718_create_patients_table.php | 48 + .../2026_03_15_054112_create_news_table.php | 38 + ...6_03_15_055324_create_categories_table.php | 29 + ...03_15_112730_create_appointments_table.php | 50 + ...2026_04_03_044049_create_doctors_table.php | 35 + ...050708_create_service_categories_table.php | 28 + ...026_04_03_050731_create_services_table.php | 36 + ...edical_record_number_to_patients_table.php | 28 + ...11_080037_create_medical_records_table.php | 36 + .../database/seeders/DatabaseSeeder.php | 32 + .../database/seeders/PermissionSeeder.php | 60 + .../database/seeders/RoleSeeder.php | 28 + .../seeders/ServiceCategorySeeder.php | 29 + .../database/seeders/ServiceSeeder.php | 72 + .../database/seeders/SettingSeeder.php | 42 + .../database/seeders/UserSeeder.php | 35 + sk-klinik.my.id/lang/id.json | 336 + sk-klinik.my.id/lang/id/actions.php | 119 + sk-klinik.my.id/lang/id/auth.php | 9 + sk-klinik.my.id/lang/id/http-statuses.php | 84 + sk-klinik.my.id/lang/id/pagination.php | 8 + sk-klinik.my.id/lang/id/passwords.php | 11 + sk-klinik.my.id/lang/id/validation.php | 288 + sk-klinik.my.id/package-lock.json | 2617 ++++ sk-klinik.my.id/package.json | 28 + sk-klinik.my.id/phpunit.xml | 36 + sk-klinik.my.id/pint.json | 3 + sk-klinik.my.id/public/.htaccess | 25 + sk-klinik.my.id/public/apple-touch-icon.png | Bin 0 -> 1662 bytes sk-klinik.my.id/public/favicon.ico | Bin 0 -> 4286 bytes sk-klinik.my.id/public/favicon.svg | 3 + sk-klinik.my.id/public/images/hero-klinik.jpg | Bin 0 -> 190595 bytes sk-klinik.my.id/public/images/logo.png | Bin 0 -> 44864 bytes sk-klinik.my.id/public/index.php | 20 + sk-klinik.my.id/public/phpliteadmin/index.php | 6177 +++++++++ .../phpliteadmin/phpliteadmin.config.php | 78 + sk-klinik.my.id/public/robots.txt | 2 + sk-klinik.my.id/resources/css/app lama.css | 67 + sk-klinik.my.id/resources/css/app.css | 69 + sk-klinik.my.id/resources/js/app.js | 23 + .../views/admin/patients/print.blade.php | 126 + .../admin/patients/verify-status.blade.php | 61 + .../views/components/action-message.blade.php | 14 + .../views/components/app-logo-icon.blade.php | 8 + .../views/components/app-logo.blade.php | 29 + .../views/components/auth-header.blade.php | 9 + .../components/auth-session-status.blade.php | 9 + .../components/desktop-user-menu.blade.php | 39 + .../views/components/guest-layout.blade.php | 90 + .../components/placeholder-pattern.blade.php | 12 + .../components/settings/layout.blade.php | 20 + .../resources/views/dashboard.blade.php | 18 + .../resources/views/dashboard/admin.blade.php | 0 .../views/dashboard/pasien.blade.php | 0 .../views/errors/maintenance.blade.php | 71 + .../views/flux/icon/book-open-text.blade.php | 47 + .../flux/icon/chevrons-up-down.blade.php | 43 + .../views/flux/icon/folder-git-2.blade.php | 45 + .../views/flux/icon/layout-grid.blade.php | 45 + .../views/flux/navlist/group.blade.php | 51 + .../resources/views/layouts/app.blade.php | 6 + .../views/layouts/app/header.blade.php | 78 + .../views/layouts/app/sidebar.blade.php | 211 + .../resources/views/layouts/auth.blade.php | 4 + .../views/layouts/auth/card.blade.php | 36 + .../views/layouts/auth/simple.blade.php | 32 + .../views/layouts/auth/split.blade.php | 53 + .../views/layouts/theme-style.blade.php | 8 + .../views/livewire/admin/categories.blade.php | 101 + .../views/livewire/admin/dashboard.blade.php | 80 + .../livewire/admin/doctor-manager.blade.php | 227 + .../livewire/admin/manage-antrean.blade.php | 695 + .../livewire/admin/news/news-create.blade.php | 66 + .../livewire/admin/news/news-edit.blade.php | 79 + .../views/livewire/admin/news/news.blade.php | 113 + .../livewire/admin/patient-history.blade.php | 99 + .../livewire/admin/patient-manager.blade.php | 384 + .../admin/permission-manager.blade.php | 98 + .../livewire/admin/role-manager.blade.php | 111 + .../livewire/admin/role-permissions.blade.php | 45 + .../livewire/admin/service-manager.blade.php | 192 + .../livewire/admin/site-settings.blade.php | 289 + .../livewire/admin/user-manager.blade.php | 113 + .../livewire/auth/confirm-password.blade.php | 28 + .../livewire/auth/forgot-password.blade.php | 31 + .../views/livewire/auth/login.blade.php | 59 + .../views/livewire/auth/register.blade.php | 67 + .../livewire/auth/reset-password.blade.php | 52 + .../auth/two-factor-challenge.blade.php | 95 + .../livewire/auth/verify-email.blade.php | 29 + .../views/livewire/guest/about-page.blade.php | 191 + .../livewire/guest/complete-profile.blade.php | 97 + .../views/livewire/guest/dashboard.blade.php | 3 + .../livewire/guest/doctor-page.blade.php | 51 + .../guest/landing-page.blade copy 2.php | 243 + .../guest/landing-page.blade copy.php | 205 + .../livewire/guest/landing-page.blade.php | 261 + .../views/livewire/guest/news-index.blade.php | 57 + .../views/livewire/guest/news-show.blade.php | 67 + .../patient/booking-antrean.blade.php | 241 + .../patient/complete-profile.blade.php | 97 + .../livewire/patient/dashboard.blade.php | 115 + .../patient/news/news-detail.blade.php | 64 + .../livewire/patient/news/news.blade.php | 79 + .../patient/patient-profile.blade.php | 138 + .../livewire/settings/appearance.blade.php | 13 + .../settings/delete-user-form.blade.php | 34 + .../views/livewire/settings/profile.blade.php | 47 + .../livewire/settings/security.blade.php | 239 + .../two-factor/recovery-codes.blade.php | 89 + .../resources/views/partials/head.blade.php | 31 + .../views/partials/settings-heading.blade.php | 5 + .../resources/views/welcome.blade.php | 278 + sk-klinik.my.id/routes/admin.php | 78 + sk-klinik.my.id/routes/console.php | 8 + sk-klinik.my.id/routes/guest.php | 9 + sk-klinik.my.id/routes/patient.php | 22 + sk-klinik.my.id/routes/settings.php | 28 + sk-klinik.my.id/routes/web.php | 66 + sk-klinik.my.id/storage/app/.gitignore | 4 + .../storage/app/private/.gitignore | 2 + sk-klinik.my.id/storage/app/public/.gitignore | 2 + sk-klinik.my.id/storage/framework/.gitignore | 9 + .../storage/framework/cache/.gitignore | 3 + .../storage/framework/cache/data/.gitignore | 2 + .../storage/framework/sessions/.gitignore | 2 + .../storage/framework/testing/.gitignore | 2 + .../storage/framework/views/.gitignore | 2 + sk-klinik.my.id/storage/logs/.gitignore | 2 + .../tests/Feature/Auth/AuthenticationTest.php | 81 + .../Feature/Auth/EmailVerificationTest.php | 88 + .../Feature/Auth/PasswordConfirmationTest.php | 21 + .../tests/Feature/Auth/PasswordResetTest.php | 81 + .../tests/Feature/Auth/RegistrationTest.php | 41 + .../Feature/Auth/TwoFactorChallengeTest.php | 42 + .../tests/Feature/DashboardTest.php | 27 + sk-klinik.my.id/tests/Feature/ExampleTest.php | 18 + .../Feature/Settings/ProfileUpdateTest.php | 90 + .../tests/Feature/Settings/SecurityTest.php | 123 + sk-klinik.my.id/tests/TestCase.php | 16 + sk-klinik.my.id/tests/Unit/ExampleTest.php | 16 + sk-klinik.my.id/vite.config.js | 21 + 232 files changed, 35580 insertions(+) create mode 100644 sk-klinik.my.id/.editorconfig create mode 100644 sk-klinik.my.id/.env.example create mode 100644 sk-klinik.my.id/.gitattributes create mode 100644 sk-klinik.my.id/.github/workflows/lint.yml create mode 100644 sk-klinik.my.id/.github/workflows/tests.yml create mode 100644 sk-klinik.my.id/.gitignore create mode 100644 sk-klinik.my.id/.htaccess create mode 100644 sk-klinik.my.id/app/Actions/Fortify/CreateNewUser.php create mode 100644 sk-klinik.my.id/app/Actions/Fortify/ResetUserPassword.php create mode 100644 sk-klinik.my.id/app/Concerns/PasswordValidationRules.php create mode 100644 sk-klinik.my.id/app/Concerns/ProfileValidationRules.php create mode 100644 sk-klinik.my.id/app/Console/Commands/GeneratePatientMedicalRecordNumbers.php create mode 100644 sk-klinik.my.id/app/Http/Controllers/Admin/PatientController.php create mode 100644 sk-klinik.my.id/app/Http/Controllers/Controller.php create mode 100644 sk-klinik.my.id/app/Http/Middleware/CheckMaintenanceMode.php create mode 100644 sk-klinik.my.id/app/Livewire/Actions/Logout.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/Categories.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/Dashboard.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/DoctorManager.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/ManageAntrean.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/News.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/NewsCreate.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/NewsEdit.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/PatientHistory.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/PatientManager.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/PermissionManager.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/RoleManager.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/RolePermissions.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/ServiceManager.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/SiteSettings.php create mode 100644 sk-klinik.my.id/app/Livewire/Admin/UserManager.php create mode 100644 sk-klinik.my.id/app/Livewire/Guest/AboutPage.php create mode 100644 sk-klinik.my.id/app/Livewire/Guest/CompleteProfile.php create mode 100644 sk-klinik.my.id/app/Livewire/Guest/Dashboard.php create mode 100644 sk-klinik.my.id/app/Livewire/Guest/DoctorPage.php create mode 100644 sk-klinik.my.id/app/Livewire/Guest/LandingPage.php create mode 100644 sk-klinik.my.id/app/Livewire/Guest/NewsIndex.php create mode 100644 sk-klinik.my.id/app/Livewire/Guest/NewsShow.php create mode 100644 sk-klinik.my.id/app/Livewire/Patient/BookingAntrean.php create mode 100644 sk-klinik.my.id/app/Livewire/Patient/CompleteProfile.php create mode 100644 sk-klinik.my.id/app/Livewire/Patient/Dashboard.php create mode 100644 sk-klinik.my.id/app/Livewire/Patient/News.php create mode 100644 sk-klinik.my.id/app/Livewire/Patient/NewsDetail.php create mode 100644 sk-klinik.my.id/app/Livewire/Patient/PatientProfile.php create mode 100644 sk-klinik.my.id/app/Livewire/Settings/Appearance.php create mode 100644 sk-klinik.my.id/app/Livewire/Settings/DeleteUserForm.php create mode 100644 sk-klinik.my.id/app/Livewire/Settings/Profile.php create mode 100644 sk-klinik.my.id/app/Livewire/Settings/Security.php create mode 100644 sk-klinik.my.id/app/Livewire/Settings/TwoFactor/RecoveryCodes.php create mode 100644 sk-klinik.my.id/app/Models/Appointment.php create mode 100644 sk-klinik.my.id/app/Models/Category.php create mode 100644 sk-klinik.my.id/app/Models/Doctor.php create mode 100644 sk-klinik.my.id/app/Models/MedicalRecord.php create mode 100644 sk-klinik.my.id/app/Models/News.php create mode 100644 sk-klinik.my.id/app/Models/Patient.php create mode 100644 sk-klinik.my.id/app/Models/Service.php create mode 100644 sk-klinik.my.id/app/Models/ServiceCategory.php create mode 100644 sk-klinik.my.id/app/Models/Setting.php create mode 100644 sk-klinik.my.id/app/Models/User.php create mode 100644 sk-klinik.my.id/app/Providers/AppServiceProvider.php create mode 100644 sk-klinik.my.id/app/Providers/FortifyServiceProvider.php create mode 100644 sk-klinik.my.id/app/View/Components/GuestLayout.php create mode 100644 sk-klinik.my.id/artisan create mode 100644 sk-klinik.my.id/bootstrap/app.php create mode 100644 sk-klinik.my.id/bootstrap/cache/.gitignore create mode 100644 sk-klinik.my.id/bootstrap/providers.php create mode 100644 sk-klinik.my.id/composer.json create mode 100644 sk-klinik.my.id/composer.lock create mode 100644 sk-klinik.my.id/config/app.php create mode 100644 sk-klinik.my.id/config/auth.php create mode 100644 sk-klinik.my.id/config/cache.php create mode 100644 sk-klinik.my.id/config/database.php create mode 100644 sk-klinik.my.id/config/filesystems.php create mode 100644 sk-klinik.my.id/config/fortify.php create mode 100644 sk-klinik.my.id/config/logging.php create mode 100644 sk-klinik.my.id/config/mail.php create mode 100644 sk-klinik.my.id/config/permission.php create mode 100644 sk-klinik.my.id/config/queue.php create mode 100644 sk-klinik.my.id/config/services.php create mode 100644 sk-klinik.my.id/config/session.php create mode 100644 sk-klinik.my.id/config/toaster.php create mode 100644 sk-klinik.my.id/database - copy create mode 100644 sk-klinik.my.id/database/.gitignore create mode 100644 sk-klinik.my.id/database/factories/UserFactory.php create mode 100644 sk-klinik.my.id/database/migrations/0001_01_01_000000_create_users_table.php create mode 100644 sk-klinik.my.id/database/migrations/0001_01_01_000001_create_cache_table.php create mode 100644 sk-klinik.my.id/database/migrations/0001_01_01_000002_create_jobs_table.php create mode 100644 sk-klinik.my.id/database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_03_14_031324_create_permission_tables.php create mode 100644 sk-klinik.my.id/database/migrations/2026_03_14_031532_create_settings_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_03_14_143718_create_patients_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_03_15_054112_create_news_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_03_15_055324_create_categories_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_03_15_112730_create_appointments_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_04_03_044049_create_doctors_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_04_03_050708_create_service_categories_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_04_03_050731_create_services_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_07_11_071004_add_medical_record_number_to_patients_table.php create mode 100644 sk-klinik.my.id/database/migrations/2026_07_11_080037_create_medical_records_table.php create mode 100644 sk-klinik.my.id/database/seeders/DatabaseSeeder.php create mode 100644 sk-klinik.my.id/database/seeders/PermissionSeeder.php create mode 100644 sk-klinik.my.id/database/seeders/RoleSeeder.php create mode 100644 sk-klinik.my.id/database/seeders/ServiceCategorySeeder.php create mode 100644 sk-klinik.my.id/database/seeders/ServiceSeeder.php create mode 100644 sk-klinik.my.id/database/seeders/SettingSeeder.php create mode 100644 sk-klinik.my.id/database/seeders/UserSeeder.php create mode 100644 sk-klinik.my.id/lang/id.json create mode 100644 sk-klinik.my.id/lang/id/actions.php create mode 100644 sk-klinik.my.id/lang/id/auth.php create mode 100644 sk-klinik.my.id/lang/id/http-statuses.php create mode 100644 sk-klinik.my.id/lang/id/pagination.php create mode 100644 sk-klinik.my.id/lang/id/passwords.php create mode 100644 sk-klinik.my.id/lang/id/validation.php create mode 100644 sk-klinik.my.id/package-lock.json create mode 100644 sk-klinik.my.id/package.json create mode 100644 sk-klinik.my.id/phpunit.xml create mode 100644 sk-klinik.my.id/pint.json create mode 100644 sk-klinik.my.id/public/.htaccess create mode 100644 sk-klinik.my.id/public/apple-touch-icon.png create mode 100644 sk-klinik.my.id/public/favicon.ico create mode 100644 sk-klinik.my.id/public/favicon.svg create mode 100644 sk-klinik.my.id/public/images/hero-klinik.jpg create mode 100644 sk-klinik.my.id/public/images/logo.png create mode 100644 sk-klinik.my.id/public/index.php create mode 100644 sk-klinik.my.id/public/phpliteadmin/index.php create mode 100644 sk-klinik.my.id/public/phpliteadmin/phpliteadmin.config.php create mode 100644 sk-klinik.my.id/public/robots.txt create mode 100644 sk-klinik.my.id/resources/css/app lama.css create mode 100644 sk-klinik.my.id/resources/css/app.css create mode 100644 sk-klinik.my.id/resources/js/app.js create mode 100644 sk-klinik.my.id/resources/views/admin/patients/print.blade.php create mode 100644 sk-klinik.my.id/resources/views/admin/patients/verify-status.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/action-message.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/app-logo-icon.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/app-logo.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/auth-header.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/auth-session-status.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/desktop-user-menu.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/guest-layout.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/placeholder-pattern.blade.php create mode 100644 sk-klinik.my.id/resources/views/components/settings/layout.blade.php create mode 100644 sk-klinik.my.id/resources/views/dashboard.blade.php create mode 100644 sk-klinik.my.id/resources/views/dashboard/admin.blade.php create mode 100644 sk-klinik.my.id/resources/views/dashboard/pasien.blade.php create mode 100644 sk-klinik.my.id/resources/views/errors/maintenance.blade.php create mode 100644 sk-klinik.my.id/resources/views/flux/icon/book-open-text.blade.php create mode 100644 sk-klinik.my.id/resources/views/flux/icon/chevrons-up-down.blade.php create mode 100644 sk-klinik.my.id/resources/views/flux/icon/folder-git-2.blade.php create mode 100644 sk-klinik.my.id/resources/views/flux/icon/layout-grid.blade.php create mode 100644 sk-klinik.my.id/resources/views/flux/navlist/group.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/app.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/app/header.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/app/sidebar.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/auth.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/auth/card.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/auth/simple.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/auth/split.blade.php create mode 100644 sk-klinik.my.id/resources/views/layouts/theme-style.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/categories.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/dashboard.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/doctor-manager.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/manage-antrean.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/news/news-create.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/news/news-edit.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/news/news.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/patient-history.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/patient-manager.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/permission-manager.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/role-manager.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/role-permissions.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/service-manager.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/site-settings.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/admin/user-manager.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/auth/confirm-password.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/auth/forgot-password.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/auth/login.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/auth/register.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/auth/reset-password.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/auth/two-factor-challenge.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/auth/verify-email.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/about-page.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/complete-profile.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/dashboard.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/doctor-page.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy 2.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/news-index.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/guest/news-show.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/patient/booking-antrean.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/patient/complete-profile.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/patient/dashboard.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/patient/news/news-detail.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/patient/news/news.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/patient/patient-profile.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/settings/appearance.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/settings/delete-user-form.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/settings/profile.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/settings/security.blade.php create mode 100644 sk-klinik.my.id/resources/views/livewire/settings/two-factor/recovery-codes.blade.php create mode 100644 sk-klinik.my.id/resources/views/partials/head.blade.php create mode 100644 sk-klinik.my.id/resources/views/partials/settings-heading.blade.php create mode 100644 sk-klinik.my.id/resources/views/welcome.blade.php create mode 100644 sk-klinik.my.id/routes/admin.php create mode 100644 sk-klinik.my.id/routes/console.php create mode 100644 sk-klinik.my.id/routes/guest.php create mode 100644 sk-klinik.my.id/routes/patient.php create mode 100644 sk-klinik.my.id/routes/settings.php create mode 100644 sk-klinik.my.id/routes/web.php create mode 100644 sk-klinik.my.id/storage/app/.gitignore create mode 100644 sk-klinik.my.id/storage/app/private/.gitignore create mode 100644 sk-klinik.my.id/storage/app/public/.gitignore create mode 100644 sk-klinik.my.id/storage/framework/.gitignore create mode 100644 sk-klinik.my.id/storage/framework/cache/.gitignore create mode 100644 sk-klinik.my.id/storage/framework/cache/data/.gitignore create mode 100644 sk-klinik.my.id/storage/framework/sessions/.gitignore create mode 100644 sk-klinik.my.id/storage/framework/testing/.gitignore create mode 100644 sk-klinik.my.id/storage/framework/views/.gitignore create mode 100644 sk-klinik.my.id/storage/logs/.gitignore create mode 100644 sk-klinik.my.id/tests/Feature/Auth/AuthenticationTest.php create mode 100644 sk-klinik.my.id/tests/Feature/Auth/EmailVerificationTest.php create mode 100644 sk-klinik.my.id/tests/Feature/Auth/PasswordConfirmationTest.php create mode 100644 sk-klinik.my.id/tests/Feature/Auth/PasswordResetTest.php create mode 100644 sk-klinik.my.id/tests/Feature/Auth/RegistrationTest.php create mode 100644 sk-klinik.my.id/tests/Feature/Auth/TwoFactorChallengeTest.php create mode 100644 sk-klinik.my.id/tests/Feature/DashboardTest.php create mode 100644 sk-klinik.my.id/tests/Feature/ExampleTest.php create mode 100644 sk-klinik.my.id/tests/Feature/Settings/ProfileUpdateTest.php create mode 100644 sk-klinik.my.id/tests/Feature/Settings/SecurityTest.php create mode 100644 sk-klinik.my.id/tests/TestCase.php create mode 100644 sk-klinik.my.id/tests/Unit/ExampleTest.php create mode 100644 sk-klinik.my.id/vite.config.js diff --git a/sk-klinik.my.id/.editorconfig b/sk-klinik.my.id/.editorconfig new file mode 100644 index 0000000..a186cd2 --- /dev/null +++ b/sk-klinik.my.id/.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 + +[compose.yaml] +indent_size = 4 diff --git a/sk-klinik.my.id/.env.example b/sk-klinik.my.id/.env.example new file mode 100644 index 0000000..c0660ea --- /dev/null +++ b/sk-klinik.my.id/.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/sk-klinik.my.id/.gitattributes b/sk-klinik.my.id/.gitattributes new file mode 100644 index 0000000..4da48a8 --- /dev/null +++ b/sk-klinik.my.id/.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 + +CHANGELOG.md export-ignore +README.md export-ignore +.github/workflows/browser-tests.yml export-ignore diff --git a/sk-klinik.my.id/.github/workflows/lint.yml b/sk-klinik.my.id/.github/workflows/lint.yml new file mode 100644 index 0000000..3c53898 --- /dev/null +++ b/sk-klinik.my.id/.github/workflows/lint.yml @@ -0,0 +1,50 @@ +name: linter + +on: + push: + branches: + - develop + - main + - master + - workos + pull_request: + branches: + - develop + - main + - master + - workos + +permissions: + contents: write + +jobs: + quality: + runs-on: ubuntu-latest + environment: Testing + steps: + - uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + + - name: Add Flux Credentials Loaded From ENV + run: composer config http-basic.composer.fluxui.dev "${{ secrets.FLUX_USERNAME }}" "${{ secrets.FLUX_LICENSE_KEY }}" + + - name: Install Dependencies + run: | + composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist + npm install + + - name: Run Pint + run: composer lint + + # - name: Commit Changes + # uses: stefanzweifel/git-auto-commit-action@v7 + # with: + # commit_message: fix code style + # commit_options: '--no-verify' + # file_pattern: | + # **/* + # !.github/workflows/* diff --git a/sk-klinik.my.id/.github/workflows/tests.yml b/sk-klinik.my.id/.github/workflows/tests.yml new file mode 100644 index 0000000..3002bcf --- /dev/null +++ b/sk-klinik.my.id/.github/workflows/tests.yml @@ -0,0 +1,60 @@ +name: tests + +on: + push: + branches: + - develop + - main + - master + - workos + pull_request: + branches: + - develop + - main + - master + - workos + +jobs: + ci: + runs-on: ubuntu-latest + environment: Testing + strategy: + matrix: + php-version: ['8.4', '8.5'] + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: composer:v2 + coverage: xdebug + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install Node Dependencies + run: npm i + + - name: Add Flux Credentials Loaded From ENV + run: composer config http-basic.composer.fluxui.dev "${{ secrets.FLUX_USERNAME }}" "${{ secrets.FLUX_LICENSE_KEY }}" + + - name: Install Dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Copy Environment File + run: cp .env.example .env + + - name: Generate Application Key + run: php artisan key:generate + + - name: Build Assets + run: npm run build + + - name: Run Tests + run: ./vendor/bin/phpunit diff --git a/sk-klinik.my.id/.gitignore b/sk-klinik.my.id/.gitignore new file mode 100644 index 0000000..c7cf1fa --- /dev/null +++ b/sk-klinik.my.id/.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/sk-klinik.my.id/.htaccess b/sk-klinik.my.id/.htaccess new file mode 100644 index 0000000..c42490f --- /dev/null +++ b/sk-klinik.my.id/.htaccess @@ -0,0 +1,7 @@ + + RewriteEngine On + + # Jika request belum mengarah ke folder public, arahkan ke public + RewriteCond %{REQUEST_URI} !^/public/ + RewriteRule ^(.*)$ public/$1 [L] + \ No newline at end of file diff --git a/sk-klinik.my.id/app/Actions/Fortify/CreateNewUser.php b/sk-klinik.my.id/app/Actions/Fortify/CreateNewUser.php new file mode 100644 index 0000000..3c7c00c --- /dev/null +++ b/sk-klinik.my.id/app/Actions/Fortify/CreateNewUser.php @@ -0,0 +1,33 @@ + $input + */ + public function create(array $input): User + { + Validator::make($input, [ + ...$this->profileRules(), + 'password' => $this->passwordRules(), + ])->validate(); + + return User::create([ + 'name' => $input['name'], + 'email' => $input['email'], + 'password' => $input['password'], + ]); + } +} diff --git a/sk-klinik.my.id/app/Actions/Fortify/ResetUserPassword.php b/sk-klinik.my.id/app/Actions/Fortify/ResetUserPassword.php new file mode 100644 index 0000000..8fda5dd --- /dev/null +++ b/sk-klinik.my.id/app/Actions/Fortify/ResetUserPassword.php @@ -0,0 +1,29 @@ + $input + */ + public function reset(User $user, array $input): void + { + Validator::make($input, [ + 'password' => $this->passwordRules(), + ])->validate(); + + $user->forceFill([ + 'password' => $input['password'], + ])->save(); + } +} diff --git a/sk-klinik.my.id/app/Concerns/PasswordValidationRules.php b/sk-klinik.my.id/app/Concerns/PasswordValidationRules.php new file mode 100644 index 0000000..e858302 --- /dev/null +++ b/sk-klinik.my.id/app/Concerns/PasswordValidationRules.php @@ -0,0 +1,29 @@ +|string> + */ + protected function passwordRules(): array + { + return ['required', 'string', Password::default(), 'confirmed']; + } + + /** + * Get the validation rules used to validate the current password. + * + * @return array|string> + */ + protected function currentPasswordRules(): array + { + return ['required', 'string', 'current_password']; + } +} diff --git a/sk-klinik.my.id/app/Concerns/ProfileValidationRules.php b/sk-klinik.my.id/app/Concerns/ProfileValidationRules.php new file mode 100644 index 0000000..46e19ba --- /dev/null +++ b/sk-klinik.my.id/app/Concerns/ProfileValidationRules.php @@ -0,0 +1,50 @@ +|string>> + */ + protected function profileRules(?int $userId = null): array + { + return [ + 'name' => $this->nameRules(), + 'email' => $this->emailRules($userId), + ]; + } + + /** + * Get the validation rules used to validate user names. + * + * @return array|string> + */ + protected function nameRules(): array + { + return ['required', 'string', 'max:255']; + } + + /** + * Get the validation rules used to validate user emails. + * + * @return array|string> + */ + protected function emailRules(?int $userId = null): array + { + return [ + 'required', + 'string', + 'email', + 'max:255', + $userId === null + ? Rule::unique(User::class) + : Rule::unique(User::class)->ignore($userId), + ]; + } +} diff --git a/sk-klinik.my.id/app/Console/Commands/GeneratePatientMedicalRecordNumbers.php b/sk-klinik.my.id/app/Console/Commands/GeneratePatientMedicalRecordNumbers.php new file mode 100644 index 0000000..249203c --- /dev/null +++ b/sk-klinik.my.id/app/Console/Commands/GeneratePatientMedicalRecordNumbers.php @@ -0,0 +1,66 @@ +orWhere('medical_record_number', '') + ->orderBy('created_at', 'asc') + ->get(); + + if ($patients->isEmpty()) { + $this->info('Semua pasien sudah memiliki nomor Rekam Medis!'); + return Command::SUCCESS; + } + + $this->info("Menemukan {$patients->count()} pasien tanpa No. RM. Memulai proses..."); + + $bar = $this->output->createProgressBar($patients->count()); + $bar->start(); + + foreach ($patients as $patient) { + // Gunakan tanggal buat pasien (created_at) agar prefix tahun-bulan sesuai waktu daftar + $prefix = 'RM' . $patient->created_at->format('ym'); + + // Cari nomor RM terakhir berdasarkan prefix bulan/tahun pasien tersebut + $latestNumber = Patient::where('medical_record_number', 'like', $prefix . '%') + ->orderByDesc('medical_record_number') + ->value('medical_record_number'); + + if ($latestNumber) { + $nextNumber = ((int) substr($latestNumber, -4)) + 1; + } else { + $nextNumber = 1; + } + + // Simpan tanpa memicu event 'creating' lagi + $patient->medical_record_number = $prefix . str_pad($nextNumber, 4, '0', STR_PAD_LEFT); + $patient->saveQuietly(); // saveQuietly mencegah trigger event model + + $bar->advance(); + } + + $bar->finish(); + $this->newLine(); + $this->info('Berhasil menggenerate semua No. RM untuk pasien lama!'); + + return Command::SUCCESS; + } +} + diff --git a/sk-klinik.my.id/app/Http/Controllers/Admin/PatientController.php b/sk-klinik.my.id/app/Http/Controllers/Admin/PatientController.php new file mode 100644 index 0000000..e0a81e1 --- /dev/null +++ b/sk-klinik.my.id/app/Http/Controllers/Admin/PatientController.php @@ -0,0 +1,38 @@ +load('user'); + + // Generate URL verifikasi (ganti dengan domain asli kamu nanti) + $url = route('verify.patient', $patient->nik); + + $renderer = new ImageRenderer( + new RendererStyle(200, 0), + new SvgImageBackEnd() + ); + $writer = new Writer($renderer); + + // Sekarang QR Code berisi LINK, bukan cuma angka NIK + $qrcode = $writer->writeString($url); + + return view('admin.patients.print', compact('patient', 'qrcode')); + } + + public function verify($nik) + { + $patient = Patient::with('user')->where('nik', $nik)->firstOrFail(); + return view('admin.patients.verify-status', compact('patient')); + } +} diff --git a/sk-klinik.my.id/app/Http/Controllers/Controller.php b/sk-klinik.my.id/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..8677cd5 --- /dev/null +++ b/sk-klinik.my.id/app/Http/Controllers/Controller.php @@ -0,0 +1,8 @@ +check() && auth()->user()->hasRole('admin')) { + return $next($request); + } + + // Izinkan akses ke halaman login agar admin bisa masuk untuk mematikan mode maintenance + if ($request->is('login') || $request->is('livewire*')) { + return $next($request); + } + + // Tampilkan halaman maintenance + return response()->view('errors.maintenance', [], 503); + } + + return $next($request); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Actions/Logout.php b/sk-klinik.my.id/app/Livewire/Actions/Logout.php new file mode 100644 index 0000000..45993bb --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Actions/Logout.php @@ -0,0 +1,22 @@ +logout(); + + Session::invalidate(); + Session::regenerateToken(); + + return redirect('/'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/Categories.php b/sk-klinik.my.id/app/Livewire/Admin/Categories.php new file mode 100644 index 0000000..da6ee2d --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/Categories.php @@ -0,0 +1,77 @@ + 'required|min:3|unique:categories,name', + ]; + + public function render() + { + return view('livewire.admin.categories', [ + 'categories' => Category::withCount('news') + ->where('name', 'like', '%' . $this->search . '%') + ->latest() + ->paginate(10) + ]); + } + + public function create() + { + $this->reset(['name', 'selected_id']); + $this->isModalOpen = true; + } + + public function edit(Category $category) + { + $this->selected_id = $category->id; + $this->name = $category->name; + $this->isModalOpen = true; + } + + public function save() + { + $validationRules = $this->selected_id + ? ['name' => 'required|min:3|unique:categories,name,' . $this->selected_id] + : $this->rules; + + $this->validate($validationRules); + + Category::updateOrCreate(['id' => $this->selected_id], [ + 'name' => $this->name, + 'slug' => Str::slug($this->name), + ]); + + $pesan = $this->selected_id ? 'Kategori berhasil diperbarui!' : 'Kategori baru berhasil ditambahkan!'; + Toaster::success($pesan); + + $this->isModalOpen = false; + $this->reset(['name', 'selected_id']); + } + + public function delete(Category $category) + { + // Opsional: Cek jika kategori masih punya berita + if ($category->news_count > 0) { + Toaster::error('Kategori tidak bisa dihapus karena masih memiliki berita!'); + return; + } + + $category->delete(); + Toaster::error('Kategori telah dihapus permanen.'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/Dashboard.php b/sk-klinik.my.id/app/Livewire/Admin/Dashboard.php new file mode 100644 index 0000000..75f9eea --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/Dashboard.php @@ -0,0 +1,34 @@ + [ + 'total_patients' => Patient::count(), + 'today_appointments' => Appointment::whereDate('appointment_date', $today)->count(), + 'total_doctors' => Doctor::count(), + 'published_news' => News::where('is_published', true)->count(), + ], + 'recentAppointments' => Appointment::with(['patient', 'serviceCategory']) + ->whereDate('appointment_date', $today) + ->whereIn('status', ['waiting', 'calling']) + ->orderBy('queue_number', 'asc') + ->take(5) + ->get(), + 'popularNews' => News::orderBy('view_count', 'desc')->take(5)->get(), + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/DoctorManager.php b/sk-klinik.my.id/app/Livewire/Admin/DoctorManager.php new file mode 100644 index 0000000..fd36ad7 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/DoctorManager.php @@ -0,0 +1,146 @@ +resetPage(); + } + + public function updatedFilterSpecialization() + { + $this->resetPage(); + } + + public function create() + { + $this->resetForm(); + $this->isModalOpen = true; + } + + public function edit($id) + { + $doctor = Doctor::findOrFail($id); + + $this->doctorId = $doctor->id; + $this->name = $doctor->name; + $this->specialization = $doctor->specialization; + $this->phone = $doctor->phone; + $this->email = $doctor->email; + $this->oldPhoto = $doctor->photo; + + $this->schedule = $doctor->schedule ?? [ + 'Senin' => '', + 'Selasa' => '', + 'Rabu' => '', + 'Kamis' => '', + 'Jumat' => '', + 'Sabtu' => '', + 'Minggu' => '' + ]; + + $this->isModalOpen = true; + } + + public function save() + { + $this->validate([ + 'name' => 'required|string|max:255', + 'specialization' => 'required|string|max:255', + 'phone' => 'required|string|max:20', + 'email' => 'nullable|email', + 'photo' => 'nullable|image|max:2048', // 2MB + ]); + + // Upload foto jika ada + $photoPath = $this->oldPhoto; + + if ($this->photo) { + $photoPath = $this->photo->store('doctors', 'public'); + } + + Doctor::updateOrCreate( + ['id' => $this->doctorId], + [ + 'name' => $this->name, + 'specialization' => $this->specialization, + 'phone' => $this->phone, + 'email' => $this->email, + 'schedule' => $this->schedule, + 'photo' => $photoPath, + ] + ); + + $this->isModalOpen = false; + $this->resetForm(); + + Toaster::success('Data dokter berhasil disimpan.'); + } + + public function delete($id) + { + Doctor::findOrFail($id)->delete(); + Toaster::success('Data dokter berhasil dihapus.'); + } + + private function resetForm() + { + $this->doctorId = null; + $this->name = ''; + $this->specialization = ''; + $this->phone = ''; + $this->email = ''; + $this->photo = null; + $this->oldPhoto = null; + + $this->schedule = [ + 'Senin' => '', + 'Selasa' => '', + 'Rabu' => '', + 'Kamis' => '', + 'Jumat' => '', + 'Sabtu' => '', + 'Minggu' => '', + ]; + } + + public function render() + { + $query = Doctor::query(); + + if ($this->search) { + $query->where(function ($q) { + $q->where('name', 'like', "%{$this->search}%") + ->orWhere('specialization', 'like', "%{$this->search}%"); + }); + } + + if ($this->filterSpecialization) { + $query->where('specialization', $this->filterSpecialization); + } + + return view('livewire.admin.doctor-manager', [ + 'doctors' => $query->latest()->paginate(10), + 'specializations' => Doctor::select('specialization')->distinct()->pluck('specialization') + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/ManageAntrean.php b/sk-klinik.my.id/app/Livewire/Admin/ManageAntrean.php new file mode 100644 index 0000000..7999de1 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/ManageAntrean.php @@ -0,0 +1,411 @@ + ['except' => ''], + 'current_tab' => ['except' => 'active'], + 'filter_doctor' => ['except' => ''] + ]; + + public function mount() + { + // Default ke tanggal hari ini jika tidak ada di URL + $this->search_date = $this->search_date ?? date('Y-m-d'); + } + + public function updatedSearchDate() + { + $this->resetPage(); + } + + public function updatedFilterDoctor() + { + $this->resetPage(); + } + + public function updatedCurrentTab() + { + $this->resetPage(); + } + + /** + * Fungsi Utama Update Status & Trigger Suara + */ + public function updateStatus($id, $status) + { + $appointment = Appointment::with(['patient', 'doctor', 'serviceCategory'])->findOrFail($id); + + // LOGIKA KHUSUS JIKA STATUS 'CALLING' + if ($status === 'calling') { + // Matikan pasien lain yang sedang 'calling' di dokter yang sama agar tidak bentrok + Appointment::where('doctor_id', $appointment->doctor_id) + ->whereDate('appointment_date', $this->search_date) + ->where('status', 'calling') + ->where('id', '!=', $id) + ->update(['status' => 'waiting']); + + // Kirim event suara ke Browser + $this->dispatch( + 'play-calling-sound', + name: $appointment->patient->name, + number: $appointment->queue_number, + poli: $appointment->serviceCategory->name ?? 'Ruang Pemeriksaan', + doctor: $appointment->doctor->name ?? '' + ); + } + + $appointment->update(['status' => $status]); + + $message = match ($status) { + 'calling' => 'Pasien dipanggil ke ruang periksa.', + 'finished' => 'Pemeriksaan telah selesai.', + 'cancelled' => 'Antrean berhasil dibatalkan.', + 'skipped' => 'Pasien ditandai terlambat.', + default => 'Status berhasil diperbarui.' + }; + + Toaster::success($message); + } + + /** + * Panggil Ulang Pasien (Hanya trigger suara) + */ + public function recall($id) + { + $appointment = Appointment::with(['patient', 'doctor', 'serviceCategory'])->findOrFail($id); + + $this->dispatch( + 'play-calling-sound', + name: $appointment->patient->name, + number: $appointment->queue_number, + poli: $appointment->serviceCategory->name ?? 'Ruang Pemeriksaan', + doctor: $appointment->doctor->name ?? '' + ); + + Toaster::info("Memanggil ulang antrean nomor #{$appointment->queue_number}"); + } + + /** + * Tandai Dilewati dan Langsung Panggil Berikutnya + */ + public function skipAndNext($id) + { + $appointment = Appointment::findOrFail($id); + $appointment->update(['status' => 'skipped']); + + Toaster::warning("Pasien #{$appointment->queue_number} ditandai dilewati."); + + $this->callNext(); + } + + /** + * Kembalikan Status (Undo) + */ + public function undoStatus($id) + { + $appointment = Appointment::findOrFail($id); + $appointment->update(['status' => 'waiting']); + + Toaster::info("Antrean #{$appointment->queue_number} dikembalikan ke status menunggu."); + } + + /** + * Panggil Pasien Berikutnya secara Otomatis + */ + public function callNext() + { + $query = Appointment::where('status', 'waiting') + ->whereDate('appointment_date', $this->search_date); + + // Jika sedang filter dokter tertentu + if (!empty($this->filter_doctor)) { + $next = $query->where('doctor_id', $this->filter_doctor) + ->orderBy('queue_number', 'asc') + ->first(); + } + // Jika mode Global (Semua Dokter) + else { + $next = $query->orderBy('created_at', 'asc')->first(); + } + + if ($next) { + // Sinkronkan filter ke dokter pasien tersebut jika di mode global + if (empty($this->filter_doctor)) { + $this->filter_doctor = $next->doctor_id; + } + + $this->updateStatus($next->id, 'calling'); + Toaster::success("Memanggil berikutnya: #{$next->queue_number}"); + } else { + Toaster::error('Tidak ada pasien dalam antrean menunggu.'); + } + } + + /** + * Panggil Berdasarkan Input Nomor Manual + */ + public function callSpecificNumber() + { + if (empty($this->target_number)) { + Toaster::error('Masukkan nomor antrean.'); + return; + } + + $query = Appointment::where('queue_number', $this->target_number) + ->whereDate('appointment_date', $this->search_date) + ->whereIn('status', ['waiting', 'skipped']); + + if (!empty($this->filter_doctor)) { + $query->where('doctor_id', $this->filter_doctor); + } + + $results = $query->get(); + + if ($results->count() === 0) { + Toaster::error("Nomor #{$this->target_number} tidak ditemukan."); + } elseif ($results->count() > 1 && empty($this->filter_doctor)) { + Toaster::warning("Ada beberapa nomor sama. Pilih dokter dahulu."); + } else { + $target = $results->first(); + $this->filter_doctor = $target->doctor_id; + $this->updateStatus($target->id, 'calling'); + $this->target_number = ''; + } + } + + /** + * Pindahkan Pasien ke Dokter/Poli Lain + */ + public function transferPatient($id, $newDoctorId) + { + $appointment = Appointment::findOrFail($id); + + // Cari nomor terakhir di dokter tujuan hari ini + $lastQueue = Appointment::where('doctor_id', $newDoctorId) + ->whereDate('appointment_date', $this->search_date) + ->max('queue_number') ?? 0; + + $appointment->update([ + 'doctor_id' => $newDoctorId, + 'queue_number' => $lastQueue + 1, + 'status' => 'waiting' + ]); + + Toaster::success("Pasien berhasil dipindahkan ke Dokter/Poli tujuan."); + } + + /** + * Modal Tiket + */ + public function showTicketModal($id) + { + $this->selectedAppointment = Appointment::with(['patient', 'doctor', 'serviceCategory'])->findOrFail($id); + $this->js("Flux.modal('ticket-modal').show()"); + } + + /** + * Walk-in Registration + */ + public function openWalkInModal() + { + $this->reset(['walkin_patient_id', 'walkin_doctor_id', 'walkin_service_id', 'walkin_notes']); + if ($this->filter_doctor) $this->walkin_doctor_id = $this->filter_doctor; + $this->js("Flux.modal('walkin-modal').show()"); + } + + protected function validationAttributes() + { + return [ + 'walkin_patient_id' => 'pasien', + 'walkin_doctor_id' => 'dokter', + 'walkin_service_id' => 'poli/layanan', + ]; + } + + public function saveWalkIn() + { + // 1. Validasi pastikan ID tersebut ada di tabel patients + $this->validate([ + 'walkin_patient_id' => 'required|exists:patients,id', + 'walkin_doctor_id' => 'required|exists:doctors,id', + 'walkin_service_id' => 'required|exists:service_categories,id', + ]); + + // 2. AMBIL DATA PASIEN UNTUK MENDAPATKAN USER_ID NYA + $patientData = \App\Models\Patient::with('user')->find($this->walkin_patient_id); + + if (!$patientData || !$patientData->user_id) { + Toaster::error('Gagal memproses data pengguna pasien.'); + return; + } + + $lastQueue = Appointment::where('doctor_id', $this->walkin_doctor_id) + ->whereDate('appointment_date', $this->search_date) + ->max('queue_number') ?? 0; + + // 3. Simpan appointment menggunakan USER_ID (karena database Anda mendefinisikan patient_id sebagai ID User) + $appointment = Appointment::create([ + 'patient_id' => $patientData->user_id, // Gunakan user_id dari tabel patients + 'doctor_id' => $this->walkin_doctor_id, + 'service_category_id' => $this->walkin_service_id, + 'appointment_date' => $this->search_date, + 'queue_number' => $lastQueue + 1, + 'notes' => $this->walkin_notes, + 'status' => 'waiting', + 'created_by' => auth()->id(), + ]); + + // Ambil data lengkap termasuk relasi untuk dikirim ke JS cetak + $this->dispatch('print-after-save', data: [ + 'number' => str_pad($appointment->queue_number, 2, '0', STR_PAD_LEFT), + 'name' => $patientData->user->name ?? 'Tanpa Nama', + 'poli' => $appointment->serviceCategory->name ?? 'UMUM', + 'doctor' => $appointment->doctor->name ?? '-', + 'date' => $appointment->created_at->translatedFormat('d M Y, H:i') . ' WIB', + ]); + + $this->js("Flux.modal('walkin-modal').close()"); + Toaster::success('Pendaftaran Walk-in berhasil.'); + + $this->reset(['walkin_patient_id', 'walkin_notes']); + } + + public function render() + { + // Query Dasar berdasarkan Tanggal dan Filter Dokter + $baseQuery = Appointment::with(['patient', 'doctor', 'serviceCategory']) + ->whereDate('appointment_date', $this->search_date) + ->when($this->filter_doctor, function ($q) { + return $q->where('doctor_id', $this->filter_doctor); + }); + + // Filter Tabel berdasarkan Tab Aktif + $tableQuery = (clone $baseQuery); + if ($this->current_tab === 'active') { + $tableQuery->whereIn('status', ['waiting', 'calling', 'skipped']); + } else { + $tableQuery->where('status', $this->current_tab); + } + + return view('livewire.admin.manage-antrean', [ + 'appointments' => $tableQuery->orderBy('queue_number', 'asc')->paginate(10), + 'currentCalling' => (clone $baseQuery)->where('status', 'calling')->first(), + 'stats' => [ + 'total' => (clone $baseQuery)->count(), + 'waiting' => (clone $baseQuery)->whereIn('status', ['waiting', 'skipped'])->count(), + 'finished' => (clone $baseQuery)->where('status', 'finished')->count(), + ], + 'doctors' => Doctor::all(), + 'services' => ServiceCategory::all(), + 'patients' => strlen($this->search_patient_name) >= 3 + ? User::query() + ->has('patient') // Hanya user yang sudah punya data di tabel patients + ->with('patient') + ->where(function ($q) { + $q->where('name', 'like', '%' . $this->search_patient_name . '%') + ->orWhereHas('patient', function ($query) { + $query->where('nik', 'like', '%' . $this->search_patient_name . '%'); + }); + }) + ->limit(10) + ->get() + : [], + ]); + } + + public function startMedicalRecord($appointmentId) + { + // 1. Ambil data janji temu beserta relasinya + $this->currentExamining = Appointment::with(['doctor', 'serviceCategory'])->find($appointmentId); + + if ($this->currentExamining) { + // 2. Karena 'patient_id' di appointments adalah ID USER, kita langsung cari nama user-nya di sini + $userPasien = \App\Models\User::find($this->currentExamining->patient_id); + + // 3. Kita simpan nama aslinya ke dalam properti baru agar bisa dipanggil dengan aman di Blade + $this->currentPatientName = $userPasien ? $userPasien->name : 'Tidak Diketahui'; + + // Set form default + $this->symptoms = $this->currentExamining->notes; + $this->diagnosis = ''; + $this->treatment = ''; + $this->doctor_notes = ''; + + // Munculkan Modal + $this->js("Flux.modal('medical-record-modal').show()"); + } + } + + public function saveMedicalRecord() + { + $this->validate([ + 'symptoms' => 'required', + 'diagnosis' => 'required', + ]); + + $actualPatient = \App\Models\Patient::where('user_id', $this->currentExamining->patient_id)->first(); + + if (! $actualPatient) { + session()->flash('error', 'Data Pasien tidak ditemukan di sistem.'); + return; + } + + // Simpan ke database dengan ID Patient yang benar + MedicalRecord::create([ + 'patient_id' => $actualPatient->id, // Sekarang menggunakan ID Patient asli (Bukan 52 lagi) + 'appointment_id' => $this->currentExamining->id, + 'doctor_id' => $this->currentExamining->doctor_id, + 'symptoms' => $this->symptoms, + 'diagnosis' => $this->diagnosis, + 'treatment' => $this->treatment, + 'notes' => $this->doctor_notes, + ]); + + // Update status antrean menjadi Selesai (finished) + $this->currentExamining->update([ + 'status' => 'finished' + ]); + + $this->js("Flux.modal('medical-record-modal').close()"); + $this->reset(['currentExamining', 'symptoms', 'diagnosis', 'treatment', 'doctor_notes']); + + session()->flash('message', 'Pemeriksaan selesai dan Rekam Medis berhasil disimpan.'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/News.php b/sk-klinik.my.id/app/Livewire/Admin/News.php new file mode 100644 index 0000000..029e63f --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/News.php @@ -0,0 +1,54 @@ +resetPage(); + } + + public function togglePublish($id) + { + $news = NewsModel::findOrFail($id); + $news->is_published = !$news->is_published; + $news->save(); + + Toaster::info('Status publikasi berhasil diubah.'); + } + + public function delete($id) + { + $news = NewsModel::findOrFail($id); + + // Hapus file fisik gambar jika ada + if ($news->image) { + Storage::disk('public')->delete($news->image); + } + + $news->delete(); + Toaster::error('Berita telah dihapus permanen.'); + } + + public function render() + { + return view('livewire.admin.news.news', [ + 'news' => NewsModel::with('category') + ->where('title', 'like', '%' . $this->search . '%') + ->latest() + ->paginate(10) + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/NewsCreate.php b/sk-klinik.my.id/app/Livewire/Admin/NewsCreate.php new file mode 100644 index 0000000..e7f2d6d --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/NewsCreate.php @@ -0,0 +1,56 @@ + 'required|min:5|unique:news,title', + 'category_id' => 'required|exists:categories,id', + 'image' => 'nullable|image|max:2048', // Max 2MB + 'content' => 'required|min:20', + ]; + + public function save() + { + $this->validate(); + + // Proses upload gambar + $imagePath = $this->image ? $this->image->store('news', 'public') : null; + + News::create([ + 'title' => $this->title, + 'slug' => Str::slug($this->title), + 'category_id' => $this->category_id, + 'image' => $imagePath, + 'content' => $this->content, + 'user_id' => auth()->id(), + 'is_published' => $this->is_published, + ]); + + Toaster::success('Berita berhasil diterbitkan!'); + + return redirect()->route('admin.news'); + } + + public function render() + { + return view('livewire.admin.news.news-create', [ + 'categories' => Category::all() + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/NewsEdit.php b/sk-klinik.my.id/app/Livewire/Admin/NewsEdit.php new file mode 100644 index 0000000..ba2e748 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/NewsEdit.php @@ -0,0 +1,77 @@ +news = $news; + $this->title = $news->title; + $this->category_id = $news->category_id; + $this->content = $news->content; + + // Memastikan tipe data boolean agar checkbox tercentang + $this->is_published = (bool) $news->is_published; + + $this->oldImage = $news->image; + } + + protected function rules() + { + return [ + 'title' => 'required|min:5|unique:news,title,' . $this->news->id, + 'category_id' => 'required|exists:categories,id', + 'image' => 'nullable|image|max:2048', + 'content' => 'required|min:20', + 'is_published' => 'boolean', + ]; + } + + public function save() + { + $this->validate(); + + $data = [ + 'title' => $this->title, + 'category_id' => $this->category_id, + 'content' => $this->content, + 'is_published' => $this->is_published, + ]; + + if ($this->image) { + // Hapus gambar lama jika user upload gambar baru + if ($this->oldImage) { + Storage::disk('public')->delete($this->oldImage); + } + $data['image'] = $this->image->store('news', 'public'); + } + + $this->news->update($data); + + Toaster::success('Berita berhasil diperbarui!'); + + return redirect()->route('admin.news'); + } + + public function render() + { + return view('livewire.admin.news.news-edit', [ + 'categories' => Category::all() + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/PatientHistory.php b/sk-klinik.my.id/app/Livewire/Admin/PatientHistory.php new file mode 100644 index 0000000..1ee35bc --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/PatientHistory.php @@ -0,0 +1,32 @@ +patient = $patient->load('user'); + } + + public function render() + { + // Mengambil data rekam medis pasien yang diurutkan dari pemeriksaan terbaru[cite: 4, 7] + $medicalRecords = $this->patient->medicalRecords() + ->with(['doctor', 'appointment.serviceCategory']) // Load relasi dokter dan poli[cite: 3, 7] + ->latest() + ->paginate(5); + + return view('livewire.admin.patient-history', [ + 'medicalRecords' => $medicalRecords, // Mengirim variabel medicalRecords ke view + ])->layout('layouts.app'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/PatientManager.php b/sk-klinik.my.id/app/Livewire/Admin/PatientManager.php new file mode 100644 index 0000000..960260f --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/PatientManager.php @@ -0,0 +1,243 @@ + 'Nama pasien', + 'createForm.email' => 'Alamat email', + 'createForm.nik' => 'NIK', + 'createForm.gender' => 'Jenis kelamin', + 'createForm.date_of_birth' => 'Tanggal lahir', + 'createForm.place_of_birth' => 'Tempat lahir', + 'createForm.phone' => 'Nomor telepon', + 'createForm.address' => 'Alamat domisili', + 'createForm.insurance_type' => 'Jenis penjaminan', + 'createForm.insurance_number' => 'Nomor kartu', + + // Alias untuk Form Edit + 'editForm.name' => 'Nama pasien', + 'editForm.nik' => 'NIK', + 'editForm.gender' => 'Jenis kelamin', + 'editForm.date_of_birth' => 'Tanggal lahir', + 'editForm.place_of_birth' => 'Tempat lahir', + 'editForm.phone' => 'Nomor telepon', + 'editForm.address' => 'Alamat domisili', + 'editForm.insurance_type' => 'Jenis penjaminan', + 'editForm.insurance_number' => 'Nomor kartu', + ]; + } + + // Tambahkan properti untuk menangani perubahan UI di modal + public $createForm = [ + 'name' => '', + 'email' => '', + 'nik' => '', + 'gender' => '', + 'blood_type' => '', + 'place_of_birth' => '', + 'date_of_birth' => '', + 'phone' => '', + 'address' => '', + 'emergency_contact_name' => '', + 'emergency_contact_relation' => '', + 'emergency_contact_phone' => '', + 'insurance_type' => 'Umum', + 'insurance_number' => '', + ]; + + public function store() + { + $this->validate([ + 'createForm.name' => 'required|string|max:255', + 'createForm.email' => 'required|email|unique:users,email', + 'createForm.nik' => 'required|digits:16|unique:patients,nik', + 'createForm.gender' => 'required|in:L,P', + 'createForm.date_of_birth' => 'required|date', + 'createForm.phone' => 'required', + 'createForm.address' => 'required', + 'createForm.insurance_type' => 'required', + ]); + + // DB Transaction direkomendasikan karena insert ke 2 tabel + DB::transaction(function () { + $user = User::create([ + 'name' => $this->createForm['name'], + 'email' => $this->createForm['email'], + 'password' => bcrypt($this->createForm['nik']), + ]); + + $user->patient()->create([ + 'nik' => $this->createForm['nik'], + 'gender' => $this->createForm['gender'], + 'blood_type' => $this->createForm['blood_type'], + 'place_of_birth' => $this->createForm['place_of_birth'], + 'date_of_birth' => $this->createForm['date_of_birth'], + 'phone' => $this->createForm['phone'], + 'address' => $this->createForm['address'], + 'emergency_contact_name' => $this->createForm['emergency_contact_name'], + 'emergency_contact_relation' => $this->createForm['emergency_contact_relation'], + 'emergency_contact_phone' => $this->createForm['emergency_contact_phone'], + 'insurance_type' => $this->createForm['insurance_type'], + 'insurance_number' => $this->createForm['insurance_number'], + ]); + + $user->syncRoles('patient'); + }); + + $this->js("Flux.modal('add-patient').close()"); + Toaster::success('Data pasien berhasil didaftarkan. password default adalah NIK pasien.'); + $this->reset('createForm'); + } + + // Fungsi untuk reset form tambah + public function create() + { + $this->reset('createForm'); + $this->createForm['insurance_type'] = 'Umum'; // default + $this->js("Flux.modal('add-patient').show()"); + } + + // Properti untuk Form Edit + public $editForm = [ + 'id' => null, + 'name' => '', + 'nik' => '', + 'place_of_birth' => '', + 'date_of_birth' => '', + 'gender' => '', + 'blood_type' => '', + 'phone' => '', + 'address' => '', + 'emergency_contact_name' => '', + 'emergency_contact_phone' => '', + 'emergency_contact_relation' => '', + 'insurance_type' => '', + 'insurance_number' => '', + ]; + + public function updatedSearch() + { + $this->resetPage(); + } + + public function updatedFilterInsurance() + { + $this->resetPage(); + } + + // Fungsi membuka modal detail + public function showDetail($id) + { + $this->selectedPatient = Patient::with('user')->find($id); + $this->js("Flux.modal('patient-detail').show()"); + } + + // Fungsi memuat data ke modal edit + public function edit($id) + { + $patient = Patient::with('user')->findOrFail($id); + + $this->editForm = [ + 'id' => $patient->id, + 'name' => $patient->user->name, + 'nik' => $patient->nik, + 'place_of_birth' => $patient->place_of_birth, + 'date_of_birth' => $patient->date_of_birth, + 'gender' => $patient->gender, + 'blood_type' => $patient->blood_type, + 'phone' => $patient->phone, + 'address' => $patient->address, + 'emergency_contact_name' => $patient->emergency_contact_name, + 'emergency_contact_phone' => $patient->emergency_contact_phone, + 'emergency_contact_relation' => $patient->emergency_contact_relation, + 'insurance_type' => $patient->insurance_type, + 'insurance_number' => $patient->insurance_number, + ]; + + $this->js("Flux.modal('edit-patient').show()"); + } + + // Fungsi simpan perubahan + public function update() + { + $this->validate([ + 'editForm.name' => 'required|string|max:255', + 'editForm.nik' => 'required|digits:16|unique:patients,nik,' . $this->editForm['id'], + 'editForm.place_of_birth' => 'required', + 'editForm.date_of_birth' => 'required|date', + 'editForm.gender' => 'required|in:L,P', + 'editForm.phone' => 'required', + 'editForm.address' => 'required', + 'editForm.insurance_type' => 'required', + ]); + + $patient = Patient::findOrFail($this->editForm['id']); + + $patient->user->update(['name' => $this->editForm['name']]); + + $patient->update([ + 'nik' => $this->editForm['nik'], + 'place_of_birth' => $this->editForm['place_of_birth'], + 'date_of_birth' => $this->editForm['date_of_birth'], + 'gender' => $this->editForm['gender'], + 'blood_type' => $this->editForm['blood_type'], + 'phone' => $this->editForm['phone'], + 'address' => $this->editForm['address'], + 'emergency_contact_name' => $this->editForm['emergency_contact_name'], + 'emergency_contact_phone' => $this->editForm['emergency_contact_phone'], + 'emergency_contact_relation' => $this->editForm['emergency_contact_relation'], + 'insurance_type' => $this->editForm['insurance_type'], + 'insurance_number' => $this->editForm['insurance_number'], + ]); + + $this->js("Flux.modal('edit-patient').close()"); + Toaster::success('Data pasien berhasil diperbarui.'); + } + + public function delete($id) + { + Patient::findOrFail($id)->delete(); + Toaster::success('Data pasien berhasil dihapus.'); + } + + public function render() + { + $query = Patient::with('user'); + + if ($this->search) { + $query->where(function ($q) { + $q->where('nik', 'like', '%' . $this->search . '%') + ->orWhere('medical_record_number', 'like', '%' . $this->search . '%') + ->orWhereHas('user', function ($userQuery) { + $userQuery->where('name', 'like', '%' . $this->search . '%'); + }); + }); + } + + if ($this->filterInsurance) { + $query->where('insurance_type', $this->filterInsurance); + } + + return view('livewire.admin.patient-manager', [ + 'patients' => $query->latest()->paginate(10) + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/PermissionManager.php b/sk-klinik.my.id/app/Livewire/Admin/PermissionManager.php new file mode 100644 index 0000000..d2c44d5 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/PermissionManager.php @@ -0,0 +1,77 @@ + 'required|min:3|unique:permissions,name', + ]; + + public function render() + { + return view('livewire.admin.permission-manager', [ + 'permissions' => Permission::where('name', 'like', '%' . $this->search . '%') + ->latest() + ->paginate(10) + ]); + } + + public function create() + { + $this->reset(['name', 'permissionId']); + $this->isModalOpen = true; + } + + public function edit(Permission $permission) + { + $this->permissionId = $permission->id; + $this->name = $permission->name; + $this->isModalOpen = true; + } + + public function save() + { + $validationRules = $this->permissionId + ? ['name' => 'required|min:3|unique:permissions,name,' . $this->permissionId] + : $this->rules; + + $this->validate($validationRules); + + Permission::updateOrCreate(['id' => $this->permissionId], [ + 'name' => $this->name, + 'guard_name' => 'web' + ]); + + $pesan = $this->permissionId ? 'Permission berhasil diperbarui!' : 'Permission baru berhasil ditambahkan!'; + Toaster::success($pesan); + + $this->isModalOpen = false; + $this->reset(['name', 'permissionId']); + } + + public function delete(Permission $permission) + { + // Opsional: Proteksi permission krusial agar tidak terhapus + $protectedPermissions = ['role-list', 'role-create', 'permission-list']; + + if (in_array($permission->name, $protectedPermissions)) { + Toaster::error('Permission ini dilindungi sistem dan tidak boleh dihapus!'); + return; + } + + $permission->delete(); + Toaster::error('Permission telah dihapus.'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/RoleManager.php b/sk-klinik.my.id/app/Livewire/Admin/RoleManager.php new file mode 100644 index 0000000..9fb450b --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/RoleManager.php @@ -0,0 +1,76 @@ + 'required|min:3|unique:roles,name', + ]; + + public function render() + { + return view('livewire.admin.role-manager', [ + 'roles' => Role::where('name', 'like', '%' . $this->search . '%') + ->latest() + ->paginate(10) + ]); + } + + public function create() + { + $this->reset(['name', 'roleId']); + $this->isModalOpen = true; + } + + public function edit(Role $role) + { + $this->roleId = $role->id; + $this->name = $role->name; + $this->isModalOpen = true; + } + + public function save() + { + $validationRules = $this->roleId + ? ['name' => 'required|min:3|unique:roles,name,' . $this->roleId] + : $this->rules; + + $this->validate($validationRules); + + Role::updateOrCreate(['id' => $this->roleId], [ + 'name' => $this->name, + 'guard_name' => 'web' // Default guard + ]); + + $pesan = $this->roleId ? 'Role berhasil diperbarui!' : 'Role baru berhasil ditambahkan!'; + Toaster::success($pesan); + + $this->isModalOpen = false; + $this->reset(['name', 'roleId']); + } + + public function delete(Role $role) + { + $protectedRoles = ['admin', 'Admin', 'super-admin']; + + if (in_array($role->name, $protectedRoles)) { + Toaster::error('Role ini adalah role sistem dan tidak boleh dihapus!'); + return; + } + + $role->delete(); + Toaster::error('Role telah dihapus permanen.'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/RolePermissions.php b/sk-klinik.my.id/app/Livewire/Admin/RolePermissions.php new file mode 100644 index 0000000..62e78dd --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/RolePermissions.php @@ -0,0 +1,39 @@ +role = $role; + // Ambil permission yang sudah dimiliki role ini + $this->selectedPermissions = $role->permissions->pluck('name')->toArray(); + } + + public function save() + { + $this->role->syncPermissions($this->selectedPermissions); + Toaster::success('Hak akses untuk role ' . $this->role->name . ' berhasil diperbarui!'); + + return redirect()->route('admin.roles'); // Kembali ke daftar role + } + + public function render() + { + return view('livewire.admin.role-permissions', [ + 'allPermissions' => Permission::all()->groupBy(function($perm) { + // Opsional: Kelompokkan berdasarkan kata pertama (misal: 'user-list' jadi group 'user') + return explode('-', $perm->name)[0]; + }) + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/ServiceManager.php b/sk-klinik.my.id/app/Livewire/Admin/ServiceManager.php new file mode 100644 index 0000000..e172377 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/ServiceManager.php @@ -0,0 +1,136 @@ +resetPage(); + } + + public function updatedFilterCategory() + { + $this->resetPage(); + } + + public function create() + { + $this->resetForm(); + $this->isModalOpen = true; + } + + public function edit($id) + { + $service = Service::findOrFail($id); + + $this->serviceId = $service->id; + $this->name = $service->name; + $this->category_id = $service->category_id; + $this->description = $service->description; + $this->existingPhotos = $service->photo ?? []; // Tampilkan foto yang sudah ada + $this->isModalOpen = true; + } + + public function save() + { + $this->validate([ + 'name' => 'required', + 'category_id' => 'required', + 'photos.*' => 'image|max:2048', // Validasi tiap file (max 2MB) + ]); + + $paths = $this->existingPhotos; + if ($this->photos) { + if (!Storage::disk('public')->exists('services')) { + Storage::disk('public')->makeDirectory('services'); + } + + foreach ($this->photos as $photo) { + $paths[] = $photo->store('services', 'public'); + } + } + + Service::updateOrCreate( + ['id' => $this->serviceId], + [ + 'name' => $this->name, + 'category_id' => $this->category_id, + 'description' => $this->description, + 'photo' => $paths, + ] + ); + + $this->isModalOpen = false; + $this->resetForm(); + + Toaster::success('Data layanan berhasil disimpan.'); + } + + public function removePhoto($index) + { + unset($this->existingPhotos[$index]); + $this->existingPhotos = array_values($this->existingPhotos); + } + + public function delete($id) + { + $service = Service::findOrFail($id); + if ($service->photo) { + foreach ($service->photo as $path) { + Storage::disk('public')->delete($path); + } + } + $service->delete(); + Toaster::success('Data layanan berhasil dihapus.'); + } + + private function resetForm() + { + $this->serviceId = null; + $this->name = ''; + $this->category_id = ''; + $this->description = ''; + $this->photos = []; // Reset input file + $this->existingPhotos = []; // Reset foto yang sudah ada + } + + public function render() + { + $query = Service::with('category'); + + if ($this->search) { + $query->where('name', 'like', "%{$this->search}%"); + } + + if ($this->filterCategory) { + $query->where('category_id', $this->filterCategory); + } + + return view('livewire.admin.service-manager', [ + 'services' => $query->latest()->paginate(10), + 'categories' => ServiceCategory::pluck('name', 'id') + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/SiteSettings.php b/sk-klinik.my.id/app/Livewire/Admin/SiteSettings.php new file mode 100644 index 0000000..9100059 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/SiteSettings.php @@ -0,0 +1,136 @@ +{$key} = filter_var($value, FILTER_VALIDATE_BOOLEAN); + } elseif ($key === 'accent_color') { + $this->accent = $value; + } elseif ($key === 'base_color') { + $this->base = $value; + } elseif ($key === 'site_logo') { + $this->existing_logo = $value; + } elseif ($key === 'site_favicon') { + $this->existing_favicon = $value; + } else { + $this->{$key} = $value; + } + } + } + + public function save() + { + $this->validate([ + 'site_name' => 'required|string|max:255', + 'clinic_email' => 'nullable|email', + 'clinic_latitude' => 'nullable|string', // Validasi latitude + 'clinic_longitude' => 'nullable|string', // Validasi longitude + 'accent' => 'required', + 'base' => 'required', + 'logo' => 'nullable|image|max:1024', // Max 1MB + 'favicon' => 'nullable|image|max:512', // Max 512KB + ]); + + // Simpan Data Text + Setting::set('site_name', $this->site_name); + Setting::set('site_description', $this->site_description); + Setting::set('meta_keywords', $this->meta_keywords); + Setting::set('clinic_address', $this->clinic_address); + Setting::set('clinic_phone', $this->clinic_phone); + Setting::set('clinic_email', $this->clinic_email); + + // Simpan Data Koordinat + Setting::set('clinic_latitude', $this->clinic_latitude); + Setting::set('clinic_longitude', $this->clinic_longitude); + + Setting::set('accent_color', $this->accent); + Setting::set('base_color', $this->base); + Setting::set('social_facebook', $this->social_facebook); + Setting::set('social_instagram', $this->social_instagram); + Setting::set('social_twitter', $this->social_twitter); + + Setting::set('maintenance_mode', $this->maintenance_mode ? 'true' : 'false'); + Setting::set('registration_open', $this->registration_open ? 'true' : 'false'); + + // Handle Upload Logo + if ($this->logo) { + if ($this->existing_logo) Storage::disk('public')->delete(str_replace('/storage/', '', $this->existing_logo)); + Setting::set('site_logo', $this->logo->store('site', 'public')); + } + + // Handle Upload Favicon + if ($this->favicon) { + if ($this->existing_favicon) Storage::disk('public')->delete(str_replace('/storage/', '', $this->existing_favicon)); + Setting::set('site_favicon', $this->favicon->store('site', 'public')); + } + + Cache::forget('site_settings'); + + $this->dispatch('saved'); + + Toaster::success('Pengaturan klinik berhasil diperbarui!'); + } + + public function render() + { + return view('livewire.admin.site-settings'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Admin/UserManager.php b/sk-klinik.my.id/app/Livewire/Admin/UserManager.php new file mode 100644 index 0000000..1017229 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Admin/UserManager.php @@ -0,0 +1,108 @@ +search) { + $query->where(function ($q) { + $q->where('name', 'like', '%' . $this->search . '%') + ->orWhere('email', 'like', '%' . $this->search . '%'); + }); + } + + // Filter berdasarkan Role + if ($this->filterRole) { + $query->role($this->filterRole); // Scope dari Spatie Permission + } + + return view('livewire.admin.user-manager', [ + 'users' => $query->latest()->paginate(10), + 'roles' => Role::all() + ]); + } + + public function create() + { + $this->reset(['userId', 'name', 'email', 'password', 'selectedRole']); + $this->isModalOpen = true; + } + + public function edit(User $user) + { + $this->userId = $user->id; + $this->name = $user->name; + $this->email = $user->email; + $this->selectedRole = $user->roles->pluck('name')->first(); + $this->password = ''; // Kosongkan password saat edit + $this->isModalOpen = true; + } + + public function save() + { + $rules = [ + 'name' => 'required|string|max:255', + 'email' => 'required|email|unique:users,email,' . $this->userId, + 'selectedRole' => 'required', + ]; + + // Password hanya wajib jika user baru + if (!$this->userId) { + $rules['password'] = 'required|min:8'; + } + + $this->validate($rules); + + $data = [ + 'name' => $this->name, + 'email' => $this->email, + ]; + + if ($this->password) { + $data['password'] = Hash::make($this->password); + } + + $user = User::updateOrCreate( + ['id' => $this->userId], + $data + ); + + // Sinkronisasi Role (Spatie) + $user->syncRoles($this->selectedRole); + + Toaster::success($this->userId ? 'User berhasil diperbarui!' : 'User berhasil dibuat!'); + $this->isModalOpen = false; + } + + public function delete($id) + { + $user = User::findOrFail($id); + + if ($user->id === auth()->id()) { + Toaster::error('Anda tidak bisa menghapus akun sendiri!'); + return; + } + + $user->delete(); + Toaster::success('User telah dihapus.'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Guest/AboutPage.php b/sk-klinik.my.id/app/Livewire/Guest/AboutPage.php new file mode 100644 index 0000000..8cdd36e --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Guest/AboutPage.php @@ -0,0 +1,23 @@ + value + $this->settings = Setting::pluck('value', 'key')->toArray(); + } + + public function render() + { + return view('livewire.guest.about-page') + ->layout('components.guest-layout'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Guest/CompleteProfile.php b/sk-klinik.my.id/app/Livewire/Guest/CompleteProfile.php new file mode 100644 index 0000000..2490ab5 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Guest/CompleteProfile.php @@ -0,0 +1,85 @@ +user()->patient()->exists()) { + return redirect()->route('dashboard'); + } + } + + // Properties sesuai kolom database + public $nik, $place_of_birth, $date_of_birth, $gender, $blood_type; + public $phone, $address; + public $emergency_contact_name, $emergency_contact_phone, $emergency_contact_relation; + public $insurance_type = 'Umum'; // Default Umum + public $insurance_number; + + protected $rules = [ + 'nik' => 'required|digits:16|unique:patients,nik', + 'place_of_birth' => 'required|string', + 'date_of_birth' => 'required|date', + 'gender' => 'required|in:L,P', + 'blood_type' => 'nullable|in:A,B,AB,O,-', + 'phone' => 'required|numeric|min_digits:10', + 'address' => 'required|min:10', + 'emergency_contact_name' => 'nullable|string', + 'emergency_contact_phone' => 'nullable|numeric', + 'emergency_contact_relation' => 'nullable|string', + 'insurance_type' => 'required|in:Umum,BPJS,Asuransi Swasta', + 'insurance_number' => 'required_if:insurance_type,BPJS,Asuransi Swasta', + ]; + + public function save() + { + $this->validate(); + + try { + DB::transaction(function () { + // 1. Buat data pasien + Patient::create([ + 'user_id' => auth()->id(), + 'nik' => $this->nik, + 'place_of_birth' => $this->place_of_birth, + 'date_of_birth' => $this->date_of_birth, + 'gender' => $this->gender, + 'blood_type' => $this->blood_type, + 'phone' => $this->phone, + 'address' => $this->address, + 'insurance_type' => $this->insurance_type, + 'insurance_number' => $this->insurance_number, + ]); + + // 2. Berikan role 'patient' + $user = auth()->user(); + $user->syncRoles(['patient']); // Gunakan assignRole atau syncRoles + + // 3. Hapus role 'guest' jika ada + $user->removeRole('guest'); + }); + + Toaster::success('Profil berhasil dilengkapi!'); + + // Redirect ke dashboard agar session di-refresh + return redirect()->route('dashboard'); + } catch (\Exception $e) { + // Tampilkan error asli agar kamu tahu apa yang salah (misal: kolom kurang) + logger($e->getMessage()); + Toaster::error('Gagal simpan: ' . $e->getMessage()); + } + } + + public function render() + { + return view('livewire.guest.complete-profile'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Guest/Dashboard.php b/sk-klinik.my.id/app/Livewire/Guest/Dashboard.php new file mode 100644 index 0000000..b48e1b1 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Guest/Dashboard.php @@ -0,0 +1,13 @@ + Doctor::latest()->get() + ])->layout('components.guest-layout'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Guest/LandingPage.php b/sk-klinik.my.id/app/Livewire/Guest/LandingPage.php new file mode 100644 index 0000000..3fd78aa --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Guest/LandingPage.php @@ -0,0 +1,50 @@ +settings = Setting::pluck('value', 'key')->toArray(); + $this->services = ServiceCategory::with('services')->get(); + } + + public function showServiceDetail($id) + { + // Memuat service lengkap beserta kategori pendukungnya + $this->selectedService = Service::with('category')->find($id); + + if ($this->selectedService) { + $this->showModal = true; + } + } + + public function closeModal() + { + $this->selectedService = null; + $this->showModal = false; + } + + public function copyAddress() + { + Toaster::success('Alamat berhasil disalin!'); + } + + public function render() + { + return view('livewire.guest.landing-page') + ->layout('components.guest-layout'); + } +} \ No newline at end of file diff --git a/sk-klinik.my.id/app/Livewire/Guest/NewsIndex.php b/sk-klinik.my.id/app/Livewire/Guest/NewsIndex.php new file mode 100644 index 0000000..7a57dc2 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Guest/NewsIndex.php @@ -0,0 +1,23 @@ + News::where('is_published', true) + ->with('category') + ->latest() + ->paginate(9) + ])->layout('components.guest-layout', ['title' => 'Berita & Edukasi Kesehatan']); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Guest/NewsShow.php b/sk-klinik.my.id/app/Livewire/Guest/NewsShow.php new file mode 100644 index 0000000..605eeec --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Guest/NewsShow.php @@ -0,0 +1,36 @@ +is_published) { + abort(404); + } + + $this->news = $news; + + // Tambah view count + $this->news->increment('view_count'); + } + + public function render() + { + return view('livewire.guest.news-show') + ->layout('components.guest-layout', [ + 'title' => $this->news->title, + // SEO: Mengambil potongan konten untuk meta description + 'description' => Str::limit(strip_tags($this->news->content), 160) + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Patient/BookingAntrean.php b/sk-klinik.my.id/app/Livewire/Patient/BookingAntrean.php new file mode 100644 index 0000000..427fc37 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Patient/BookingAntrean.php @@ -0,0 +1,126 @@ + 'Tanggal pendaftaran wajib diisi.', + 'appointment_date.after_or_equal' => 'Tanggal pendaftaran tidak boleh di masa lalu.', + 'service_category_id.required' => 'Poli / Layanan wajib dipilih.', + 'service_category_id.exists' => 'Poli yang dipilih tidak valid.', + 'doctor_id.required' => 'Dokter wajib dipilih.', + 'doctor_id.exists' => 'Dokter yang dipilih tidak valid.', + 'notes.required' => 'Keluhan singkat wajib diisi.', + 'notes.max' => 'Keluhan singkat tidak boleh lebih dari 255 karakter.', + ]; + + public function mount() + { + $this->appointment_date = date('Y-m-d'); + + $this->service_category_id = \App\Models\ServiceCategory::first()?->id; + $this->doctor_id = \App\Models\Doctor::first()?->id; + } + + // Fungsi untuk membatalkan antrean + public function cancelAppointment($id) + { + $appointment = Appointment::where('patient_id', Auth::id()) + ->where('status', 'waiting') + ->findOrFail($id); + + $appointment->update(['status' => 'cancelled']); + Toaster::success('Antrean berhasil dibatalkan.'); + } + + // Fungsi untuk mengambil data tiket dan buka modal + public function showTicketModal($id) + { + $this->selectedAppointment = Appointment::with('patient')->findOrFail($id); + + // Pastikan variabel showTicket tetap true jika Anda masih menggunakannya untuk @if di blade + $this->showTicket = true; + + // Membuka modal menggunakan Flux Javascript API + $this->js("Flux.modal('ticket-modal').show()"); + } + + public function save() + { + $this->validate([ + 'appointment_date' => 'required|date|after_or_equal:today', + 'doctor_id' => 'required|exists:doctors,id', + 'service_category_id' => 'required|exists:service_categories,id', + 'notes' => 'required|string|max:255', + ]); + + // Cek duplikasi: 1 pasien, 1 hari, 1 dokter + $exists = Appointment::where('patient_id', Auth::id()) + ->where('doctor_id', $this->doctor_id) + ->whereDate('appointment_date', $this->appointment_date) + ->exists(); + + if ($exists) { + Toaster::error('Anda sudah terdaftar untuk dokter ini di tanggal tersebut.'); + return; + } + + // Nomor antrean spesifik per DOKTER dan per TANGGAL + $lastQueue = Appointment::where('doctor_id', $this->doctor_id) + ->whereDate('appointment_date', $this->appointment_date) + ->max('queue_number') ?? 0; + + $newApp = Appointment::create([ + 'patient_id' => Auth::id(), + 'doctor_id' => $this->doctor_id, + 'service_category_id' => $this->service_category_id, + 'appointment_date' => $this->appointment_date, + 'queue_number' => $lastQueue + 1, + 'notes' => $this->notes, + 'status' => 'waiting', + 'created_by' => Auth::id(), + ]); + + $this->reset(['notes', 'doctor_id', 'service_category_id']); + $this->showTicketModal($newApp->id); + } + + public function render() + { + // Ambil nomor yang statusnya 'calling' hari ini + $currentCalling = Appointment::whereDate('appointment_date', date('Y-m-d')) + ->where('status', 'calling') + ->when($this->filter_doctor, function ($query) { + return $query->where('doctor_id', $this->filter_doctor); + }) + ->with(['patient', 'doctor', 'serviceCategory']) // Eager load agar tidak error + ->latest('updated_at') // Ambil yang paling baru dipanggil + ->first(); + + return view('livewire.patient.booking-antrean', [ + 'myAppointments' => Appointment::where('patient_id', Auth::id()) + ->latest() + ->paginate(5), + 'currentCalling' => $currentCalling, // Kirim ke view + 'categories' => \App\Models\ServiceCategory::all(), // Data Poli + 'doctors' => \App\Models\Doctor::all(), // Data Dokter + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Patient/CompleteProfile.php b/sk-klinik.my.id/app/Livewire/Patient/CompleteProfile.php new file mode 100644 index 0000000..d6291f4 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Patient/CompleteProfile.php @@ -0,0 +1,77 @@ + 'required|digits:16|unique:patients,nik', + 'place_of_birth' => 'required|string', + 'date_of_birth' => 'required|date', + 'gender' => 'required|in:L,P', + 'blood_type' => 'nullable|in:A,B,AB,O,-', + 'phone' => 'required|numeric|min_digits:10', + 'address' => 'required|min:10', + 'emergency_contact_name' => 'nullable|string', + 'emergency_contact_phone' => 'nullable|numeric', + 'emergency_contact_relation' => 'nullable|string', + 'insurance_type' => 'required|in:Umum,BPJS,Asuransi Swasta', + 'insurance_number' => 'required_if:insurance_type,BPJS,Asuransi Swasta', + ]; + + public function save() + { + $this->validate(); + + try { + DB::transaction(function () { + // 1. Buat data pasien + Patient::create([ + 'user_id' => auth()->id(), + 'nik' => $this->nik, + 'place_of_birth' => $this->place_of_birth, + 'date_of_birth' => $this->date_of_birth, + 'gender' => $this->gender, + 'blood_type' => $this->blood_type, + 'phone' => $this->phone, + 'address' => $this->address, + 'insurance_type' => $this->insurance_type, + 'insurance_number' => $this->insurance_number, + ]); + + // 2. Berikan role 'patient' + $user = auth()->user(); + $user->syncRoles('patient'); // Gunakan assignRole atau syncRoles + + // 3. Hapus role 'guest' jika ada + $user->removeRole('guest'); + }); + + Toaster::success('Profil berhasil dilengkapi!'); + + // Redirect ke dashboard agar session di-refresh + return redirect()->route('dashboard'); + } catch (\Exception $e) { + // Tampilkan error asli agar kamu tahu apa yang salah (misal: kolom kurang) + logger($e->getMessage()); + Toaster::error('Gagal simpan: ' . $e->getMessage()); + } + } + + public function render() + { + return view('livewire.patient.complete-profile'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Patient/Dashboard.php b/sk-klinik.my.id/app/Livewire/Patient/Dashboard.php new file mode 100644 index 0000000..1fa9116 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Patient/Dashboard.php @@ -0,0 +1,36 @@ +id(); + $today = date('Y-m-d'); + + return view('livewire.patient.dashboard', [ + 'currentAppointment' => Appointment::with(['serviceCategory', 'doctor']) + ->where('patient_id', $userId) + ->whereDate('appointment_date', $today) + ->whereIn('status', ['waiting', 'calling']) + ->first(), + + 'history' => Appointment::with(['serviceCategory']) + ->where('patient_id', $userId) + ->where('appointment_date', '<', $today) + ->orderBy('appointment_date', 'desc') + ->take(3) + ->get(), + + 'news' => News::where('is_published', true) + ->latest() // Sama dengan orderBy('created_at', 'desc') + ->take(3) + ->get(), + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Patient/News.php b/sk-klinik.my.id/app/Livewire/Patient/News.php new file mode 100644 index 0000000..df5564e --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Patient/News.php @@ -0,0 +1,36 @@ + ['except' => ''], + ]; + + public function updatedSearch() + { + $this->resetPage(); + } + + public function render() + { + return view('livewire.patient.news.news', [ + 'news' => NewsModel::with('category') + ->where('is_published', true) // Pastikan hanya berita yang terbit + ->where('title', 'like', '%' . $this->search . '%') + ->latest() + ->paginate(12) // Gunakan kelipatan 3 atau 4 untuk grid yang pas + ]); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Patient/NewsDetail.php b/sk-klinik.my.id/app/Livewire/Patient/NewsDetail.php new file mode 100644 index 0000000..946c10c --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Patient/NewsDetail.php @@ -0,0 +1,24 @@ +increment('view_count'); + + $this->news = $news->load('category'); + } + + public function render() + { + return view('livewire.patient.news.news-detail') + ->layout('layouts.app'); // Sesuaikan dengan layout Anda + } +} diff --git a/sk-klinik.my.id/app/Livewire/Patient/PatientProfile.php b/sk-klinik.my.id/app/Livewire/Patient/PatientProfile.php new file mode 100644 index 0000000..60fbc44 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Patient/PatientProfile.php @@ -0,0 +1,80 @@ +user()->load('patient'); + + if ($user->patient) { + $this->patient = $user->patient; + + // Mapping data dari database ke properti form + $this->name = $user->name; + $this->nik = $this->patient->nik; + $this->place_of_birth = $this->patient->place_of_birth; + $this->date_of_birth = $this->patient->date_of_birth; + $this->gender = $this->patient->gender; + $this->blood_type = $this->patient->blood_type; + $this->phone = $this->patient->phone; + $this->address = $this->patient->address; + $this->insurance_type = $this->patient->insurance_type; + $this->insurance_number = $this->patient->insurance_number; + $this->emergency_contact_name = $this->patient->emergency_contact_name; + $this->emergency_contact_phone = $this->patient->emergency_contact_phone; + $this->emergency_contact_relation = $this->patient->emergency_contact_relation; + } else { + // Jika user punya role patient tapi data di tabel patients hilang + return redirect()->route('patient.complete-profile')->with('error', 'Data profil Anda tidak ditemukan. Silakan lengkapi profil Anda terlebih dahulu.'); + } + } + + public function updateProfile() + { + // Validasi data + $this->validate([ + 'phone' => 'required|numeric', + 'address' => 'required|min:10', + 'place_of_birth' => 'required', + 'date_of_birth' => 'required|date', + 'insurance_type' => 'required', + 'insurance_number' => 'required_if:insurance_type,BPJS,Asuransi Swasta', + ]); + + // Update data di tabel patients + $this->patient->update([ + 'place_of_birth' => $this->place_of_birth, + 'date_of_birth' => $this->date_of_birth, + 'gender' => $this->gender, + 'blood_type' => $this->blood_type, + 'phone' => $this->phone, + 'address' => $this->address, + 'insurance_type' => $this->insurance_type, + 'insurance_number' => $this->insurance_number, + 'emergency_contact_name' => $this->emergency_contact_name, + 'emergency_contact_phone' => $this->emergency_contact_phone, + 'emergency_contact_relation' => $this->emergency_contact_relation, + ]); + + Toaster::success('Profil berhasil diperbarui.'); + } + + public function render() + { + return view('livewire.patient.patient-profile'); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Settings/Appearance.php b/sk-klinik.my.id/app/Livewire/Settings/Appearance.php new file mode 100644 index 0000000..7550e32 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Settings/Appearance.php @@ -0,0 +1,12 @@ +validate([ + 'password' => $this->currentPasswordRules(), + ]); + + tap(Auth::user(), $logout(...))->delete(); + + $this->redirect('/', navigate: true); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Settings/Profile.php b/sk-klinik.my.id/app/Livewire/Settings/Profile.php new file mode 100644 index 0000000..2082cea --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Settings/Profile.php @@ -0,0 +1,81 @@ +name = Auth::user()->name; + $this->email = Auth::user()->email; + } + + /** + * Update the profile information for the currently authenticated user. + */ + public function updateProfileInformation(): void + { + $user = Auth::user(); + + $validated = $this->validate($this->profileRules($user->id)); + + $user->fill($validated); + + if ($user->isDirty('email')) { + $user->email_verified_at = null; + } + + $user->save(); + + $this->dispatch('profile-updated', name: $user->name); + } + + /** + * Send an email verification notification to the current user. + */ + public function resendVerificationNotification(): void + { + $user = Auth::user(); + + if ($user->hasVerifiedEmail()) { + $this->redirectIntended(default: route('dashboard', absolute: false)); + + return; + } + + $user->sendEmailVerificationNotification(); + + Session::flash('status', 'verification-link-sent'); + } + + #[Computed] + public function hasUnverifiedEmail(): bool + { + return Auth::user() instanceof MustVerifyEmail && ! Auth::user()->hasVerifiedEmail(); + } + + #[Computed] + public function showDeleteUser(): bool + { + return ! Auth::user() instanceof MustVerifyEmail + || (Auth::user() instanceof MustVerifyEmail && Auth::user()->hasVerifiedEmail()); + } +} diff --git a/sk-klinik.my.id/app/Livewire/Settings/Security.php b/sk-klinik.my.id/app/Livewire/Settings/Security.php new file mode 100644 index 0000000..f5263f3 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Settings/Security.php @@ -0,0 +1,224 @@ +canManageTwoFactor = Features::canManageTwoFactorAuthentication(); + + if ($this->canManageTwoFactor) { + if (Fortify::confirmsTwoFactorAuthentication() && is_null(auth()->user()->two_factor_confirmed_at)) { + $disableTwoFactorAuthentication(auth()->user()); + } + + $this->twoFactorEnabled = auth()->user()->hasEnabledTwoFactorAuthentication(); + $this->requiresConfirmation = Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm'); + } + } + + /** + * Update the password for the currently authenticated user. + */ + public function updatePassword(): void + { + try { + $validated = $this->validate([ + 'current_password' => $this->currentPasswordRules(), + 'password' => $this->passwordRules(), + ]); + } catch (ValidationException $e) { + $this->reset('current_password', 'password', 'password_confirmation'); + + throw $e; + } + + Auth::user()->update([ + 'password' => $validated['password'], + ]); + + $this->reset('current_password', 'password', 'password_confirmation'); + + $this->dispatch('password-updated'); + } + + /** + * Enable two-factor authentication for the user. + */ + public function enable(EnableTwoFactorAuthentication $enableTwoFactorAuthentication): void + { + $enableTwoFactorAuthentication(auth()->user()); + + if (! $this->requiresConfirmation) { + $this->twoFactorEnabled = auth()->user()->hasEnabledTwoFactorAuthentication(); + } + + $this->loadSetupData(); + + $this->showModal = true; + } + + /** + * Load the two-factor authentication setup data for the user. + */ + private function loadSetupData(): void + { + $user = auth()->user(); + + try { + $this->qrCodeSvg = $user?->twoFactorQrCodeSvg(); + $this->manualSetupKey = decrypt($user->two_factor_secret); + } catch (Exception) { + $this->addError('setupData', 'Failed to fetch setup data.'); + + $this->reset('qrCodeSvg', 'manualSetupKey'); + } + } + + /** + * Show the two-factor verification step if necessary. + */ + public function showVerificationIfNecessary(): void + { + if ($this->requiresConfirmation) { + $this->showVerificationStep = true; + + $this->resetErrorBag(); + + return; + } + + $this->closeModal(); + } + + /** + * Confirm two-factor authentication for the user. + */ + public function confirmTwoFactor(ConfirmTwoFactorAuthentication $confirmTwoFactorAuthentication): void + { + $this->validate(); + + $confirmTwoFactorAuthentication(auth()->user(), $this->code); + + $this->closeModal(); + + $this->twoFactorEnabled = true; + } + + /** + * Reset two-factor verification state. + */ + public function resetVerification(): void + { + $this->reset('code', 'showVerificationStep'); + + $this->resetErrorBag(); + } + + /** + * Disable two-factor authentication for the user. + */ + public function disable(DisableTwoFactorAuthentication $disableTwoFactorAuthentication): void + { + $disableTwoFactorAuthentication(auth()->user()); + + $this->twoFactorEnabled = false; + } + + /** + * Close the two-factor authentication modal. + */ + public function closeModal(): void + { + $this->reset( + 'code', + 'manualSetupKey', + 'qrCodeSvg', + 'showModal', + 'showVerificationStep', + ); + + $this->resetErrorBag(); + + if (! $this->requiresConfirmation) { + $this->twoFactorEnabled = auth()->user()->hasEnabledTwoFactorAuthentication(); + } + } + + /** + * Get the current modal configuration state. + */ + public function getModalConfigProperty(): array + { + if ($this->twoFactorEnabled) { + return [ + 'title' => __('Two-factor authentication enabled'), + 'description' => __('Two-factor authentication is now enabled. Scan the QR code or enter the setup key in your authenticator app.'), + 'buttonText' => __('Close'), + ]; + } + + if ($this->showVerificationStep) { + return [ + 'title' => __('Verify authentication code'), + 'description' => __('Enter the 6-digit code from your authenticator app.'), + 'buttonText' => __('Continue'), + ]; + } + + return [ + 'title' => __('Enable two-factor authentication'), + 'description' => __('To finish enabling two-factor authentication, scan the QR code or enter the setup key in your authenticator app.'), + 'buttonText' => __('Continue'), + ]; + } +} diff --git a/sk-klinik.my.id/app/Livewire/Settings/TwoFactor/RecoveryCodes.php b/sk-klinik.my.id/app/Livewire/Settings/TwoFactor/RecoveryCodes.php new file mode 100644 index 0000000..7352d80 --- /dev/null +++ b/sk-klinik.my.id/app/Livewire/Settings/TwoFactor/RecoveryCodes.php @@ -0,0 +1,50 @@ +loadRecoveryCodes(); + } + + /** + * Generate new recovery codes for the user. + */ + public function regenerateRecoveryCodes(GenerateNewRecoveryCodes $generateNewRecoveryCodes): void + { + $generateNewRecoveryCodes(auth()->user()); + + $this->loadRecoveryCodes(); + } + + /** + * Load the recovery codes for the user. + */ + private function loadRecoveryCodes(): void + { + $user = auth()->user(); + + if ($user->hasEnabledTwoFactorAuthentication() && $user->two_factor_recovery_codes) { + try { + $this->recoveryCodes = json_decode(decrypt($user->two_factor_recovery_codes), true); + } catch (Exception) { + $this->addError('recoveryCodes', 'Failed to load recovery codes'); + + $this->recoveryCodes = []; + } + } + } +} diff --git a/sk-klinik.my.id/app/Models/Appointment.php b/sk-klinik.my.id/app/Models/Appointment.php new file mode 100644 index 0000000..a5e5929 --- /dev/null +++ b/sk-klinik.my.id/app/Models/Appointment.php @@ -0,0 +1,88 @@ + 'date', + ]; + + /** + * Relasi ke User (sebagai Pasien). + */ + public function patient() + { + return $this->belongsTo(User::class, 'patient_id'); + } + + /** + * Relasi ke Dokter (Tabel Doctors). + */ + public function doctor() + { + // Diarahkan ke model Doctor, bukan User + return $this->belongsTo(Doctor::class, 'doctor_id'); + } + + /** + * Relasi ke Kategori Layanan (Poli). + */ + public function serviceCategory() + { + return $this->belongsTo(ServiceCategory::class, 'service_category_id'); + } + + /** + * Relasi ke MedicalRecord (jika sudah ada rekam medis untuk appointment ini). + */ + public function medicalRecord() + { + return $this->hasOne(MedicalRecord::class, 'appointment_id'); + } + + /** + * Relasi ke User (siapa yang membuat data ini, Admin atau Pasien sendiri). + */ + public function creator() + { + return $this->belongsTo(User::class, 'created_by'); + } + + /** + * Scope untuk mempermudah filter antrean hari ini. + */ + public function scopeToday($query) + { + return $query->whereDate('appointment_date', today()); + } + + public static function generateNextQueue($date) + { + return self::whereDate('appointment_date', $date)->count() + 1; + } +} diff --git a/sk-klinik.my.id/app/Models/Category.php b/sk-klinik.my.id/app/Models/Category.php new file mode 100644 index 0000000..3a0ca13 --- /dev/null +++ b/sk-klinik.my.id/app/Models/Category.php @@ -0,0 +1,15 @@ +hasMany(News::class); + } +} diff --git a/sk-klinik.my.id/app/Models/Doctor.php b/sk-klinik.my.id/app/Models/Doctor.php new file mode 100644 index 0000000..dfdb323 --- /dev/null +++ b/sk-klinik.my.id/app/Models/Doctor.php @@ -0,0 +1,21 @@ + 'array', + ]; +} diff --git a/sk-klinik.my.id/app/Models/MedicalRecord.php b/sk-klinik.my.id/app/Models/MedicalRecord.php new file mode 100644 index 0000000..6ee809b --- /dev/null +++ b/sk-klinik.my.id/app/Models/MedicalRecord.php @@ -0,0 +1,25 @@ +belongsTo(Patient::class); + } + + public function doctor() + { + return $this->belongsTo(Doctor::class); + } + + public function appointment() + { + return $this->belongsTo(Appointment::class); + } +} diff --git a/sk-klinik.my.id/app/Models/News.php b/sk-klinik.my.id/app/Models/News.php new file mode 100644 index 0000000..5ae66d9 --- /dev/null +++ b/sk-klinik.my.id/app/Models/News.php @@ -0,0 +1,65 @@ +slug = Str::slug($news->title); + }); + } + + public function author() + { + return $this->belongsTo(User::class, 'user_id'); + } + + public function category() + { + return $this->belongsTo(Category::class); + } + + /** + * Accessor untuk URL Gambar + * Cara panggil di Blade: {{ $item->image_url }} + */ + public function getImageUrlAttribute() + { + if ($this->image && Storage::disk('public')->exists($this->image)) { + return asset('storage/' . $this->image); + } + + // Placeholder jika gambar tidak ada + return 'https://placehold.co/600x400/f4f4f5/10b981?text=Klinik+News'; + } + + protected function readTime(): Attribute + { + return Attribute::make( + get: function () { + $words = str_word_count(strip_tags($this->content)); + $minutes = ceil($words / 200); // 200 kata per menit + return $minutes < 1 ? 1 : $minutes; + }, + ); + } +} diff --git a/sk-klinik.my.id/app/Models/Patient.php b/sk-klinik.my.id/app/Models/Patient.php new file mode 100644 index 0000000..59f86a1 --- /dev/null +++ b/sk-klinik.my.id/app/Models/Patient.php @@ -0,0 +1,63 @@ +belongsTo(User::class, 'user_id', 'id'); + } + + public function medicalRecords() + { + return $this->hasMany(MedicalRecord::class); + } + + protected static function booted() + { + static::deleting(function ($patient) { + // Hapus user yang terhubung dengan patient ini + if ($patient->user) { + $patient->user->delete(); + } + }); + + static::creating(function ($patient) { + if (empty($patient->medical_record_number)) { + $prefix = 'RM' . now()->format('ym'); + + $latestNumber = static::where('medical_record_number', 'like', $prefix . '%') + ->orderByDesc('medical_record_number') + ->value('medical_record_number'); + + if ($latestNumber) { + $nextNumber = ((int) substr($latestNumber, -4)) + 1; + } else { + $nextNumber = 1; + } + + $patient->medical_record_number = $prefix . str_pad($nextNumber, 4, '0', STR_PAD_LEFT); + } + }); + } +} diff --git a/sk-klinik.my.id/app/Models/Service.php b/sk-klinik.my.id/app/Models/Service.php new file mode 100644 index 0000000..6b5393b --- /dev/null +++ b/sk-klinik.my.id/app/Models/Service.php @@ -0,0 +1,24 @@ + 'array', + ]; + + public function category() + { + return $this->belongsTo(ServiceCategory::class, 'category_id'); + } +} diff --git a/sk-klinik.my.id/app/Models/ServiceCategory.php b/sk-klinik.my.id/app/Models/ServiceCategory.php new file mode 100644 index 0000000..6762c47 --- /dev/null +++ b/sk-klinik.my.id/app/Models/ServiceCategory.php @@ -0,0 +1,15 @@ +hasMany(Service::class, 'category_id'); + } +} diff --git a/sk-klinik.my.id/app/Models/Setting.php b/sk-klinik.my.id/app/Models/Setting.php new file mode 100644 index 0000000..ad13032 --- /dev/null +++ b/sk-klinik.my.id/app/Models/Setting.php @@ -0,0 +1,38 @@ +first(); + + $defaults = [ + 'site_name' => 'Si Klinik', + 'site_description' => 'Sistem Informasi Klinik.', + 'accent_color' => 'indigo', + 'base_color' => 'zinc', + ]; + + if (!$setting) return $defaults[$key] ?? $default; + + if (in_array($key, ['site_logo', 'site_favicon']) && $setting->value) { + return Storage::url($setting->value); + } + + return $setting->value; + } + + // Helper untuk update atau create + public static function set($key, $value) + { + return self::updateOrCreate(['key' => $key], ['value' => $value]); + } +} diff --git a/sk-klinik.my.id/app/Models/User.php b/sk-klinik.my.id/app/Models/User.php new file mode 100644 index 0000000..d6aceea --- /dev/null +++ b/sk-klinik.my.id/app/Models/User.php @@ -0,0 +1,83 @@ + */ + use HasFactory, Notifiable, TwoFactorAuthenticatable, HasRoles; + + /** + * The attributes that are mass assignable. + * + * @var list + */ + protected $fillable = [ + 'name', + 'email', + 'password', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var list + */ + protected $hidden = [ + 'password', + 'two_factor_secret', + 'two_factor_recovery_codes', + 'remember_token', + ]; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + /** + * Get the user's initials + */ + public function initials(): string + { + return Str::of($this->name) + ->explode(' ') + ->take(2) + ->map(fn($word) => Str::substr($word, 0, 1)) + ->implode(''); + } + + protected static function booted() + { + static::created(function ($user) { + // Cari role guest, jika tidak ada maka buat otomatis + $role = Role::firstOrCreate(['name' => 'guest', 'guard_name' => 'web']); + + // Berikan role tersebut ke user baru + $user->assignRole($role); + }); + } + + public function patient() + { + return $this->hasOne(Patient::class, 'user_id', 'id'); + } +} diff --git a/sk-klinik.my.id/app/Providers/AppServiceProvider.php b/sk-klinik.my.id/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..85b1bf4 --- /dev/null +++ b/sk-klinik.my.id/app/Providers/AppServiceProvider.php @@ -0,0 +1,74 @@ +configureDefaults(); + + $settings = Cache::rememberForever('site_settings', function () { + return [ + 'name' => Setting::get('site_name', 'Nama Default'), + 'description' => Setting::get('site_description', 'Deskripsi Default'), + 'keywords' => Setting::get('meta_keywords', 'keyword1, keyword2'), + 'favicon' => Setting::get('site_favicon', ''), + 'logo' => Setting::get('site_logo', ''), + 'accent' => Setting::get('accent_color', 'indigo'), + 'base' => Setting::get('base_color', 'zinc'), + 'registration_open' => Setting::get('registration_open', 'true'), + ]; + }); + + $shades = ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950']; + + // Share satu variabel $site agar rapi + View::share('site', (object) $settings); + View::share('themeShades', $shades); + } + + /** + * Configure default behaviors for production-ready applications. + */ + protected function configureDefaults(): void + { + Date::use(CarbonImmutable::class); + + DB::prohibitDestructiveCommands( + app()->isProduction(), + ); + + Password::defaults( + fn(): ?Password => app()->isProduction() + ? Password::min(12) + ->mixedCase() + ->letters() + ->numbers() + ->symbols() + ->uncompromised() + : null, + ); + } +} diff --git a/sk-klinik.my.id/app/Providers/FortifyServiceProvider.php b/sk-klinik.my.id/app/Providers/FortifyServiceProvider.php new file mode 100644 index 0000000..c312285 --- /dev/null +++ b/sk-klinik.my.id/app/Providers/FortifyServiceProvider.php @@ -0,0 +1,82 @@ +configureActions(); + $this->configureViews(); + $this->configureRateLimiting(); + } + + /** + * Configure Fortify actions. + */ + private function configureActions(): void + { + Fortify::resetUserPasswordsUsing(ResetUserPassword::class); + Fortify::createUsersUsing(CreateNewUser::class); + } + + /** + * Configure Fortify views. + */ + private function configureViews(): void + { + Fortify::loginView(fn() => view('livewire.auth.login')); + Fortify::verifyEmailView(fn() => view('livewire.auth.verify-email')); + Fortify::twoFactorChallengeView(fn() => view('livewire.auth.two-factor-challenge')); + Fortify::confirmPasswordView(fn() => view('livewire.auth.confirm-password')); + // Fortify::registerView(fn () => view('livewire.auth.register')); + + Fortify::registerView(function () { + if (\App\Models\Setting::get('registration_open') === 'false') { + \Masmerise\Toaster\Toaster::error('Pendaftaran pasien baru sedang ditutup.'); + + return redirect()->route('login'); + } + return view('livewire.auth.register'); + }); + + Fortify::resetPasswordView(fn() => view('livewire.auth.reset-password')); + Fortify::requestPasswordResetLinkView(fn() => view('livewire.auth.forgot-password')); + } + + /** + * Configure rate limiting. + */ + private function configureRateLimiting(): void + { + RateLimiter::for('two-factor', function (Request $request) { + return Limit::perMinute(5)->by($request->session()->get('login.id')); + }); + + RateLimiter::for('login', function (Request $request) { + $throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())) . '|' . $request->ip()); + + return Limit::perMinute(5)->by($throttleKey); + }); + } +} diff --git a/sk-klinik.my.id/app/View/Components/GuestLayout.php b/sk-klinik.my.id/app/View/Components/GuestLayout.php new file mode 100644 index 0000000..0ed1f0e --- /dev/null +++ b/sk-klinik.my.id/app/View/Components/GuestLayout.php @@ -0,0 +1,26 @@ +handleCommand(new ArgvInput); + +exit($status); diff --git a/sk-klinik.my.id/bootstrap/app.php b/sk-klinik.my.id/bootstrap/app.php new file mode 100644 index 0000000..3738cb6 --- /dev/null +++ b/sk-klinik.my.id/bootstrap/app.php @@ -0,0 +1,24 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware): void { + $middleware->append(\App\Http\Middleware\CheckMaintenanceMode::class); + + $middleware->alias([ + 'role' => \Spatie\Permission\Middleware\RoleMiddleware::class, + 'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class, + 'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class, + ]); + }) + ->withExceptions(function (Exceptions $exceptions): void { + // + })->create(); diff --git a/sk-klinik.my.id/bootstrap/cache/.gitignore b/sk-klinik.my.id/bootstrap/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/bootstrap/providers.php b/sk-klinik.my.id/bootstrap/providers.php new file mode 100644 index 0000000..5ffd769 --- /dev/null +++ b/sk-klinik.my.id/bootstrap/providers.php @@ -0,0 +1,9 @@ +=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": "codezero/browser-locale", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/codezero-be/browser-locale.git", + "reference": "dd6c50e5557b06b57960df6db7f52e85ef683e5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codezero-be/browser-locale/zipball/dd6c50e5557b06b57960df6db7f52e85ef683e5e", + "reference": "dd6c50e5557b06b57960df6db7f52e85ef683e5e", + "shasum": "" + }, + "require": { + "php": "^7.0|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "phpunit/phpunit": "^6.0|^7.0|^8.0|^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "CodeZero\\BrowserLocale\\Laravel\\BrowserLocaleServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "CodeZero\\BrowserLocale\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ivan Vermeyen", + "email": "ivan@codezero.be" + } + ], + "description": "Get the most preferred locales from your visitor's browser.", + "keywords": [ + "browser", + "country", + "detect", + "language", + "locale", + "php", + "website" + ], + "support": { + "issues": "https://github.com/codezero-be/browser-locale/issues", + "source": "https://github.com/codezero-be/browser-locale/tree/3.4.0" + }, + "funding": [ + { + "url": "https://paypal.me/ivanvermeyen", + "type": "custom" + }, + { + "url": "https://ko-fi.com/ivanvermeyen", + "type": "ko_fi" + } + ], + "time": "2024-03-02T12:51:17+00:00" + }, + { + "name": "composer/class-map-generator", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/composer/class-map-generator.git", + "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/8f5fa3cc214230e71f54924bd0197a3bcc705eb1", + "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1", + "shasum": "" + }, + "require": { + "composer/pcre": "^2.1 || ^3.1", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7 || ^8" + }, + "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 || ^7 || ^8" + }, + "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.7.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2025-12-29T13:15:25+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": "composer/semver", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2025-08-20T19:15:30+00:00" + }, + { + "name": "dasprid/enum", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "shasum": "" + }, + "require": { + "php": ">=7.1 <9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "support": { + "issues": "https://github.com/DASPRiD/Enum/issues", + "source": "https://github.com/DASPRiD/Enum/tree/1.0.7" + }, + "time": "2025-09-16T12:23:56+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.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "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": "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.1.0" + }, + "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": "2025-08-10T19:31:58+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": "dragon-code/contracts", + "version": "2.24.0", + "source": { + "type": "git", + "url": "https://github.com/TheDragonCode/contracts.git", + "reference": "c21ea4fc0a399bd803a2805a7f2c989749083896" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TheDragonCode/contracts/zipball/c21ea4fc0a399bd803a2805a7f2c989749083896", + "reference": "c21ea4fc0a399bd803a2805a7f2c989749083896", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-message": "^1.0.1 || ^2.0", + "symfony/http-kernel": "^4.0 || ^5.0 || ^6.0 || ^7.0", + "symfony/polyfill-php80": "^1.23" + }, + "conflict": { + "andrey-helldar/contracts": "*" + }, + "require-dev": { + "illuminate/database": "^10.0 || ^11.0 || ^12.0", + "phpdocumentor/reflection-docblock": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "DragonCode\\Contracts\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + } + ], + "description": "A set of contracts for any project", + "keywords": [ + "contracts", + "interfaces" + ], + "support": { + "source": "https://github.com/TheDragonCode/contracts" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2025-02-23T23:11:50+00:00" + }, + { + "name": "dragon-code/pretty-array", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/TheDragonCode/pretty-array.git", + "reference": "b94034d92172a5d14a578822d68b2a8f8b5388e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TheDragonCode/pretty-array/zipball/b94034d92172a5d14a578822d68b2a8f8b5388e0", + "reference": "b94034d92172a5d14a578822d68b2a8f8b5388e0", + "shasum": "" + }, + "require": { + "dragon-code/contracts": "^2.20", + "dragon-code/support": "^6.11.2", + "ext-dom": "*", + "ext-mbstring": "*", + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^10.0 || ^11.0 || ^12.0" + }, + "suggest": { + "symfony/thanks": "Give thanks (in the form of a GitHub) to your fellow PHP package maintainers" + }, + "type": "library", + "autoload": { + "psr-4": { + "DragonCode\\PrettyArray\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + } + ], + "description": "Simple conversion of an array to a pretty view", + "keywords": [ + "andrey helldar", + "array", + "dragon", + "dragon code", + "pretty", + "pretty array" + ], + "support": { + "issues": "https://github.com/TheDragonCode/pretty-array/issues", + "source": "https://github.com/TheDragonCode/pretty-array" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2025-02-24T15:35:24+00:00" + }, + { + "name": "dragon-code/support", + "version": "6.16.0", + "source": { + "type": "git", + "url": "https://github.com/TheDragonCode/support.git", + "reference": "ab9b657a307e75f6ba5b2b39e1e45207dc1a065a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TheDragonCode/support/zipball/ab9b657a307e75f6ba5b2b39e1e45207dc1a065a", + "reference": "ab9b657a307e75f6ba5b2b39e1e45207dc1a065a", + "shasum": "" + }, + "require": { + "dragon-code/contracts": "^2.22.0", + "ext-bcmath": "*", + "ext-ctype": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.1", + "psr/http-message": "^1.0.1 || ^2.0", + "symfony/polyfill-php81": "^1.25", + "voku/portable-ascii": "^1.4.8 || ^2.0.1" + }, + "conflict": { + "andrey-helldar/support": "*" + }, + "require-dev": { + "illuminate/contracts": "^9.0 || ^10.0 || ^11.0 || ^12.0", + "phpunit/phpunit": "^9.6 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "suggest": { + "dragon-code/laravel-support": "Various helper files for the Laravel and Lumen frameworks", + "symfony/thanks": "Give thanks (in the form of a GitHub) to your fellow PHP package maintainers" + }, + "type": "library", + "extra": { + "dragon-code": { + "docs-generator": { + "preview": { + "brand": "php", + "vendor": "The Dragon Code" + } + } + } + }, + "autoload": { + "psr-4": { + "DragonCode\\Support\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + } + ], + "description": "Support package is a collection of helpers and tools for any project.", + "keywords": [ + "dragon", + "dragon-code", + "framework", + "helper", + "helpers", + "laravel", + "php", + "support", + "symfony", + "yii", + "yii2" + ], + "support": { + "issues": "https://github.com/TheDragonCode/support/issues", + "source": "https://github.com/TheDragonCode/support" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2025-02-24T14:01:52+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "shasum": "" + }, + "require": { + "php": "^8.2|^8.3|^8.4|^8.5" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.32|^2.1.31", + "phpunit/phpunit": "^8.5.48|^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.6.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2025-10-31T18:51:33+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.4.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "shasum": "" + }, + "require": { + "php": "^8.1", + "symfony/http-foundation": "^5.4|^6.4|^7.3|^8" + }, + "require-dev": { + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-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.4.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2025-12-03T09:33:47+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.4", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" + }, + "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.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:43:20+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.10.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "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.10.0" + }, + "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-08-23T22:36:01+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "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.3.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-08-22T14:34:08+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", + "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", + "jshttp/mime-db": "1.54.0.1", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "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.9.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": "2026-03-10T16:41:02+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "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.44 || ^9.6.25", + "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.5" + }, + "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-08-22T14:27:06+00:00" + }, + { + "name": "laravel-lang/actions", + "version": "1.12.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/actions.git", + "reference": "3653188fd43dbb7513a35e58e799324d110bc7d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/actions/zipball/3653188fd43dbb7513a35e58e799324d110bc7d0", + "reference": "3653188fd43dbb7513a35e58e799324d110bc7d0", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel-lang/publisher": "^14.0 || ^15.0 || ^16.0", + "php": "^8.1" + }, + "require-dev": { + "laravel-lang/status-generator": "^2.3.1", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.3 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Actions\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Actions\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + }, + { + "name": "Laravel Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "Translation of buttons and other action elements", + "keywords": [ + "actions", + "buttons", + "lang", + "languages", + "laravel", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/actions/issues", + "source": "https://github.com/Laravel-Lang/actions/tree/1.12.0" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-23T18:52:33+00:00" + }, + { + "name": "laravel-lang/attributes", + "version": "2.15.4", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/attributes.git", + "reference": "e922f224d5f20caa4467aec544b8e67b72560cf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/attributes/zipball/e922f224d5f20caa4467aec544b8e67b72560cf5", + "reference": "e922f224d5f20caa4467aec544b8e67b72560cf5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel-lang/publisher": "^14.0 || ^15.0 || ^16.0", + "php": "^8.1" + }, + "require-dev": { + "laravel-lang/status-generator": "^1.19 || ^2.0", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Attributes\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Attributes\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://github.com/Laravel-Lang" + } + ], + "description": "Translation of form element names", + "keywords": [ + "attributes", + "fields", + "form", + "lang", + "languages", + "laravel", + "messages", + "translations", + "validation" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/attributes/issues", + "source": "https://github.com/Laravel-Lang/attributes/tree/2.15.4" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-03-03T22:33:55+00:00" + }, + { + "name": "laravel-lang/common", + "version": "6.7.2", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/common.git", + "reference": "b2e3089c960106d053b47df3cc66497730130448" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/common/zipball/b2e3089c960106d053b47df3cc66497730130448", + "reference": "b2e3089c960106d053b47df3cc66497730130448", + "shasum": "" + }, + "require": { + "laravel-lang/actions": "^1.9", + "laravel-lang/attributes": "^2.12", + "laravel-lang/http-statuses": "^3.8", + "laravel-lang/json-fallback": "^2.2", + "laravel-lang/lang": "^13.12 || ^14.0 || ^15.5.1", + "laravel-lang/locales": "^2.10", + "laravel-lang/models": "^1.3", + "laravel-lang/moonshine": "^1.2", + "laravel-lang/publisher": "^16.5", + "laravel-lang/routes": "^1.7", + "laravel-lang/starter-kits": "^1.0", + "php": "^8.1" + }, + "require-dev": { + "dragon-code/support": "^6.13", + "orchestra/testbench": "^8.17 || ^9.1.2 || ^10.0", + "phpunit/phpunit": "^10.5.20 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.4 || ^7.1.1" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laravel-Lang Team", + "homepage": "https://github.com/Laravel-Lang" + }, + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + } + ], + "description": "Easily connect the necessary language packs to the application", + "keywords": [ + "Laravel-lang", + "actions", + "attribute", + "attributes", + "breeze", + "buttons", + "cashier", + "fortify", + "framework", + "http", + "http-status", + "http-status-code", + "i18n", + "jetstream", + "lang", + "language", + "languages", + "laravel", + "locale", + "locales", + "localization", + "localizations", + "moonshine", + "nova", + "publisher", + "spark", + "translation", + "translations", + "ui" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/common/issues", + "source": "https://github.com/Laravel-Lang/common" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-14T22:00:53+00:00" + }, + { + "name": "laravel-lang/config", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/config.git", + "reference": "e7cc52bd5695e017ab996a00ee57d81c3232e6e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/config/zipball/e7cc52bd5695e017ab996a00ee57d81c3232e6e2", + "reference": "e7cc52bd5695e017ab996a00ee57d81c3232e6e2", + "shasum": "" + }, + "require": { + "archtechx/enums": "^1.0", + "illuminate/config": "^10.0 || ^11.0 || ^12.0", + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.6", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^8.23 || ^9.1 || ^10.0", + "pestphp/pest": "^2.34 || ^3.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Config\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Config\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The Laravel-Lang config package", + "keywords": [ + "Laravel-lang", + "Settings", + "config", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "localizations", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/config/issues", + "source": "https://github.com/Laravel-Lang/config/tree/1.16.0" + }, + "time": "2026-01-21T07:36:30+00:00" + }, + { + "name": "laravel-lang/http-statuses", + "version": "3.12.1", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/http-statuses.git", + "reference": "4f1cfeb3df179bdcd1c40bb57cc5c7f2a11278b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/http-statuses/zipball/4f1cfeb3df179bdcd1c40bb57cc5c7f2a11278b4", + "reference": "4f1cfeb3df179bdcd1c40bb57cc5c7f2a11278b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel-lang/publisher": "^14.1 || ^15.0 || ^16.0", + "php": "^8.1" + }, + "require-dev": { + "laravel-lang/status-generator": "^1.19 || ^2.0", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\HttpStatuses\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\HttpStatuses\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://github.com/Laravel-Lang" + } + ], + "description": "Translation of HTTP statuses", + "keywords": [ + "http", + "lang", + "languages", + "laravel", + "messages", + "status", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/http-statuses/issues", + "source": "https://github.com/Laravel-Lang/http-statuses/tree/3.12.1" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-02-05T13:53:17+00:00" + }, + { + "name": "laravel-lang/json-fallback", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/json-fallback.git", + "reference": "0172de25e6cc3c5b26a7c8b778ff4e37f4d913f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/json-fallback/zipball/0172de25e6cc3c5b26a7c8b778ff4e37f4d913f4", + "reference": "0172de25e6cc3c5b26a7c8b778ff4e37f4d913f4", + "shasum": "" + }, + "require": { + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "illuminate/translation": "^10.0 || ^11.0 || ^12.0", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^8.0 || ^9.0 || ^10.0", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\JsonFallback\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://github.com/andrey-helldar" + }, + { + "name": "Felipe Dsdev", + "homepage": "https://github.com/felipe-dsdev" + } + ], + "description": "Adds support for fallback JSON string translation", + "support": { + "issues": "https://github.com/Laravel-Lang/json-fallback/issues", + "source": "https://github.com/Laravel-Lang/json-fallback/tree/2.2.1" + }, + "time": "2025-06-23T09:38:43+00:00" + }, + { + "name": "laravel-lang/lang", + "version": "15.28.5", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/lang.git", + "reference": "ccc092506de639d8cc86bb0d5d05d66cf91c1ef8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/ccc092506de639d8cc86bb0d5d05d66cf91c1ef8", + "reference": "ccc092506de639d8cc86bb0d5d05d66cf91c1ef8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel-lang/publisher": "^16.0", + "php": "^8.2" + }, + "conflict": { + "laravel/framework": "<11.0.7" + }, + "require-dev": { + "dragon-code/codestyler": "^6.0", + "laravel-lang/status-generator": "^2.11", + "phpunit/phpunit": "^11.0 || ^12.0", + "symfony/var-dumper": "^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Lang\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Lang\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laravel-Lang Team", + "homepage": "https://github.com/Laravel-Lang" + } + ], + "description": "List of 126 languages for Laravel Framework, Laravel Jetstream, Laravel Fortify, Laravel Breeze, Laravel Cashier, Laravel Nova, Laravel Spark and Laravel UI", + "keywords": [ + "lang", + "languages", + "laravel", + "lpm" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/lang/issues", + "source": "https://github.com/Laravel-Lang/lang" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-03-03T07:40:07+00:00" + }, + { + "name": "laravel-lang/locale-list", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/locale-list.git", + "reference": "48e61c7f0a957420d4aaf5d35653889c25c4e2d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/locale-list/zipball/48e61c7f0a957420d4aaf5d35653889c25c4e2d4", + "reference": "48e61c7f0a957420d4aaf5d35653889c25c4e2d4", + "shasum": "" + }, + "require": { + "archtechx/enums": "^0.3.2 || ^1.0", + "php": "^8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\LocaleList\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "List of localizations available in Laravel Lang projects", + "keywords": [ + "Laravel-lang", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/locale-list/issues", + "source": "https://github.com/Laravel-Lang/locale-list" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-20T08:17:15+00:00" + }, + { + "name": "laravel-lang/locales", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/locales.git", + "reference": "8c1d2383ced70a919b3c2f430589be6c81663087" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/locales/zipball/8c1d2383ced70a919b3c2f430589be6c81663087", + "reference": "8c1d2383ced70a919b3c2f430589be6c81663087", + "shasum": "" + }, + "require": { + "archtechx/enums": "^0.3.2 || ^1.0", + "dragon-code/support": "^6.11.3", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/config": "^1.12", + "laravel-lang/locale-list": "^1.5", + "laravel-lang/native-country-names": "^1.5", + "laravel-lang/native-currency-names": "^1.6", + "laravel-lang/native-locale-names": "^2.5", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^8.0 || ^9.0 || ^10.0", + "pestphp/pest": "^2.24.1 || ^3.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Locales\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Locales\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "Basic functionality for working with localizations", + "keywords": [ + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/locales/issues", + "source": "https://github.com/Laravel-Lang/locales" + }, + "time": "2025-02-24T20:38:10+00:00" + }, + { + "name": "laravel-lang/models", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/models.git", + "reference": "972d58cd72034f6484876148f1c0bbbb90b2ebdf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/models/zipball/972d58cd72034f6484876148f1c0bbbb90b2ebdf", + "reference": "972d58cd72034f6484876148f1c0bbbb90b2ebdf", + "shasum": "" + }, + "require": { + "composer/class-map-generator": "^1.3", + "dragon-code/support": "^6.13", + "illuminate/database": "^10.0 || ^11.0 || ^12.0", + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/config": "^1.12", + "laravel-lang/locales": "^2.10.0", + "laravel/prompts": ">=0.1", + "php": "^8.1" + }, + "require-dev": { + "laravel/pint": "^1.20", + "orchestra/testbench": "^8.0 || ^9.0 || ^10.0", + "pestphp/pest": "^2.34 || ^3.0 || ^4.0", + "pestphp/pest-plugin-laravel": "^2.4 || ^3.0 || ^4.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Models\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Models\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro", + "role": "Maintainer" + }, + { + "name": "Andrey Sokolov", + "email": "walfireru@gmail.com", + "homepage": "https://github.com/Quiss", + "role": "Usability consultant" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://github.com/Laravel-Lang" + } + ], + "description": "Easy and fast way to localize models", + "keywords": [ + "database", + "l18n", + "languages", + "laravel", + "locales", + "localization", + "models", + "translate", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/models/issues", + "source": "https://github.com/Laravel-Lang/models" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-14T22:02:36+00:00" + }, + { + "name": "laravel-lang/moonshine", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/moonshine.git", + "reference": "5daace4284fb706f735b172740bce52f990d2359" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/moonshine/zipball/5daace4284fb706f735b172740bce52f990d2359", + "reference": "5daace4284fb706f735b172740bce52f990d2359", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel-lang/publisher": "^15.0 || ^16.4.1", + "php": "^8.1" + }, + "require-dev": { + "dragon-code/support": "^6.15.2", + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/lang": "^14.8 || ^15.14", + "laravel-lang/status-generator": "^2.12", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.3 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\MoonShine\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\MoonShine\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "Translation for MoonShine admin panel", + "keywords": [ + "lang", + "languages", + "laravel", + "moonshine", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/moonshine/issues", + "source": "https://github.com/Laravel-Lang/moonshine/tree/1.8.0" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-02-01T09:24:41+00:00" + }, + { + "name": "laravel-lang/native-country-names", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/native-country-names.git", + "reference": "66a82c28c5c820239671035aa019012414d5894f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/native-country-names/zipball/66a82c28c5c820239671035aa019012414d5894f", + "reference": "66a82c28c5c820239671035aa019012414d5894f", + "shasum": "" + }, + "require": { + "dragon-code/support": "^6.11", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.5", + "pestphp/pest": "^2.24.3 || ^3.0", + "punic/punic": "^3.8", + "symfony/console": "^6.3 || ^7.0", + "symfony/process": "^6.3 || ^7.0", + "symfony/var-dumper": "^6.3 || ^7.0", + "vlucas/phpdotenv": "^5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\NativeCountryNames\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The project contains native translations of country names", + "keywords": [ + "Laravel-lang", + "countries", + "country", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "territories", + "territory", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/native-country-names/issues", + "source": "https://github.com/Laravel-Lang/native-country-names" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-21T17:13:07+00:00" + }, + { + "name": "laravel-lang/native-currency-names", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/native-currency-names.git", + "reference": "564f05c2034d76166431704f5d965067dd8c80f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/native-currency-names/zipball/564f05c2034d76166431704f5d965067dd8c80f0", + "reference": "564f05c2034d76166431704f5d965067dd8c80f0", + "shasum": "" + }, + "require": { + "dragon-code/support": "^6.11", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.2", + "pestphp/pest": "^2.24.3 || ^3.0", + "punic/punic": "^3.8", + "symfony/console": "^6.3 || ^7.0", + "symfony/process": "^6.3 || ^7.0", + "symfony/var-dumper": "^6.3 || ^7.0", + "vlucas/phpdotenv": "^5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\NativeCurrencyNames\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The project contains native translations of currency names", + "keywords": [ + "Laravel-lang", + "currency", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/native-currency-names/issues", + "source": "https://github.com/Laravel-Lang/native-currency-names" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-21T17:17:17+00:00" + }, + { + "name": "laravel-lang/native-locale-names", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/native-locale-names.git", + "reference": "e1e510e9d2699ed7c41453582e5f9efc74d858b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/native-locale-names/zipball/e1e510e9d2699ed7c41453582e5f9efc74d858b3", + "reference": "e1e510e9d2699ed7c41453582e5f9efc74d858b3", + "shasum": "" + }, + "require": { + "dragon-code/support": "^6.11", + "ext-json": "*", + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.31 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.2", + "pestphp/pest": "^2.24.3 || ^3.0", + "punic/punic": "^3.8", + "symfony/console": "^6.3 || ^7.0", + "symfony/process": "^6.3 || ^7.0", + "symfony/var-dumper": "^6.3 || ^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\NativeLocaleNames\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The project contains native translations of locale names", + "keywords": [ + "Laravel-lang", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/native-locale-names/issues", + "source": "https://github.com/Laravel-Lang/native-locale-names" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-21T17:15:48+00:00" + }, + { + "name": "laravel-lang/publisher", + "version": "16.7.1", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/publisher.git", + "reference": "b58d236ba3b5bebb4cfc87500b52f620ead4485b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/publisher/zipball/b58d236ba3b5bebb4cfc87500b52f620ead4485b", + "reference": "b58d236ba3b5bebb4cfc87500b52f620ead4485b", + "shasum": "" + }, + "require": { + "composer/semver": "^3.4", + "dragon-code/pretty-array": "^4.1", + "dragon-code/support": "^6.11.3", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "illuminate/console": "^10.0 || ^11.0 || ^12.0", + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/config": "^1.12", + "laravel-lang/locales": "^2.10", + "league/commonmark": "^2.4.1", + "league/config": "^1.2", + "php": "^8.1" + }, + "conflict": { + "laravel-lang/attributes": "<2.0", + "laravel-lang/http-statuses": "<3.0", + "laravel-lang/lang": "<11.0" + }, + "require-dev": { + "laravel-lang/json-fallback": "^2.2", + "orchestra/testbench": "^8.14 || ^9.0 || ^10.0", + "phpunit/phpunit": "^10.4.2 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.3.6 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Publisher\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Publisher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "Localization publisher for your Laravel application", + "keywords": [ + "Laravel-lang", + "breeze", + "cashier", + "fortify", + "framework", + "i18n", + "jetstream", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "localizations", + "lpm", + "lumen", + "nova", + "publisher", + "spark", + "trans", + "translation", + "translations", + "validations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/publisher/issues", + "source": "https://github.com/Laravel-Lang/publisher" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-14T22:00:51+00:00" + }, + { + "name": "laravel-lang/routes", + "version": "1.10.1", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/routes.git", + "reference": "b2352d04358823bdcffb02986463dea245fac781" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/routes/zipball/b2352d04358823bdcffb02986463dea245fac781", + "reference": "b2352d04358823bdcffb02986463dea245fac781", + "shasum": "" + }, + "require": { + "codezero/browser-locale": "^3.4", + "dragon-code/support": "^6.13", + "illuminate/config": "^10.0 || ^11.0 || ^12.0", + "illuminate/http": "^10.0 || ^11.0 || ^12.0", + "illuminate/routing": "^10.0 || ^11.0 || ^12.0", + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/config": "^1.13", + "laravel-lang/locales": "^2.10", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^8.23 || ^9.1 || ^10.0", + "pestphp/pest": "^2.34 || ^3.0", + "pestphp/pest-plugin-laravel": "^2.4 || ^3.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Routes\\ServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "helpers/functions.php" + ], + "psr-4": { + "LaravelLang\\Routes\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://github.com/Laravel-Lang" + } + ], + "description": "Easy and fast way to localize routes", + "keywords": [ + "l18n", + "languages", + "laravel", + "localization", + "routes", + "translate", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/routes/issues", + "source": "https://github.com/Laravel-Lang/routes" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-01-14T13:37:36+00:00" + }, + { + "name": "laravel-lang/starter-kits", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/starter-kits.git", + "reference": "c1f3b36949bb7084013b361e5ab0f3734663d84d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/starter-kits/zipball/c1f3b36949bb7084013b361e5ab0f3734663d84d", + "reference": "c1f3b36949bb7084013b361e5ab0f3734663d84d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel-lang/publisher": "^16.6", + "php": "^8.1" + }, + "require-dev": { + "laravel-lang/status-generator": "^2.13", + "phpunit/phpunit": "^11.0 || ^12.0", + "symfony/var-dumper": "^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\StarterKits\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\StarterKits\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "Translations for Laravel Starter Kits", + "keywords": [ + "i18n", + "lang", + "languages", + "laravel", + "starter-kit", + "starter-kits", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/starter-kits/issues", + "source": "https://github.com/Laravel-Lang/starter-kits/tree/1.9.0" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2026-02-28T00:57:54+00:00" + }, + { + "name": "laravel/fortify", + "version": "v1.36.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/fortify.git", + "reference": "cad8bfeb63f6818f173d40090725c565c92651d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/fortify/zipball/cad8bfeb63f6818f173d40090725c565c92651d4", + "reference": "cad8bfeb63f6818f173d40090725c565c92651d4", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "^3.0", + "ext-json": "*", + "illuminate/console": "^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "php": "^8.1", + "pragmarx/google2fa": "^9.0" + }, + "require-dev": { + "orchestra/testbench": "^8.36|^9.15|^10.8|^11.0", + "phpstan/phpstan": "^1.10" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Fortify\\FortifyServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Fortify\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Backend controllers and scaffolding for Laravel authentication.", + "keywords": [ + "auth", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/fortify/issues", + "source": "https://github.com/laravel/fortify" + }, + "time": "2026-03-10T19:59:49+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.54.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "325497463e7599cd14224c422c6e5dd2fe832868" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/325497463e7599cd14224c422c6e5dd2fe832868", + "reference": "325497463e7599cd14224c422c6e5dd2fe832868", + "shasum": "" + }, + "require": { + "brick/math": "^0.11|^0.12|^0.13|^0.14", + "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.8.1", + "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.33", + "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-php85": "^1.33", + "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/json-schema": "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/reflection": "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", + "opis/json-schema": "^2.4.1", + "orchestra/testbench-core": "^10.9.0", + "pda/pheanstalk": "^5.0.6|^7.0.0", + "php-http/discovery": "^1.15", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3|^3.0", + "resend/resend-php": "^0.10.0|^1.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 generate fake data using the fake() helper (^1.23).", + "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|^3.0).", + "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|^1.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/Reflection/helpers.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/", + "src/Illuminate/Reflection/" + ] + } + }, + "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": "2026-03-10T20:25:56+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.3.14", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "9f0e371244eedfe2ebeaa72c79c54bb5df6e0176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/9f0e371244eedfe2ebeaa72c79c54bb5df6e0176", + "reference": "9f0e371244eedfe2ebeaa72c79c54bb5df6e0176", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/console": "^6.2|^7.0|^8.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|^13.0", + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3|^3.4|^4.0", + "phpstan/phpstan": "^1.12.28", + "phpstan/phpstan-mockery": "^1.1.3" + }, + "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.14" + }, + "time": "2026-03-01T09:02:38+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.10", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/870fc81d2f879903dfc5b60bf8a0f94a1609e669", + "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.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": "2026-02-20T19:59:49+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.11.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", + "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|^8.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.11.1" + }, + "time": "2026-02-06T14:12:35+00:00" + }, + { + "name": "league/commonmark", + "version": "2.8.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "84b1ca48347efdbe775426f108622a42735a6579" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/84b1ca48347efdbe775426f108622a42735a6579", + "reference": "84b1ca48347efdbe775426f108622a42735a6579", + "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 || ^8.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.9-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": "2026-03-05T21:37:03+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.32.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "254b1595b16b22dbddaaef9ed6ca9fdac4956725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/254b1595b16b22dbddaaef9ed6ca9fdac4956725", + "reference": "254b1595b16b22dbddaaef9ed6ca9fdac4956725", + "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|^2", + "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|^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.32.0" + }, + "time": "2026-02-25T17:01:41+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.31.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "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.31.0" + }, + "time": "2026-01-23T15:30:45+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.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.8", + "php": "^8.1", + "psr/http-factory": "^1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", + "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", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", + "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "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": [ + "URN", + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc2141", + "rfc3986", + "rfc3987", + "rfc6570", + "rfc8141", + "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.8.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-01-14T17:24:56+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.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", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "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 tools for parsing and resolving RFC3987/RFC3986 URI", + "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.8.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-01-15T06:54:53+00:00" + }, + { + "name": "livewire/blaze", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/livewire/blaze.git", + "reference": "20cb545a8f70a3325f17c97254bb2532a99c0731" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/livewire/blaze/zipball/20cb545a8f70a3325f17c97254bb2532a99c0731", + "reference": "20cb545a8f70a3325f17c97254bb2532a99c0731", + "shasum": "" + }, + "require": { + "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/view": "^10.0|^11.0|^12.0", + "nikic/php-parser": "^5.0", + "php": "^8.1" + }, + "conflict": { + "livewire/flux": "<2.12.1" + }, + "require-dev": { + "livewire/flux": "dev-main", + "orchestra/testbench": "^8.0|^9.0|^10.0", + "pestphp/pest": "^2.0|^3.0", + "pestphp/pest-plugin-laravel": "^2.0|^3.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Livewire\\Blaze\\BlazeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Livewire\\Blaze\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Caleb Porzio" + } + ], + "description": "A tool for optimizing Blade component performance by folding them into parent templates", + "support": { + "issues": "https://github.com/livewire/blaze/issues", + "source": "https://github.com/livewire/blaze/tree/v1.0.7" + }, + "time": "2026-03-12T14:25:42+00:00" + }, + { + "name": "livewire/flux", + "version": "v2.13.0", + "source": { + "type": "git", + "url": "https://github.com/livewire/flux.git", + "reference": "741be2d4526e90b97c7a59e079a2f27ecdce2461" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/livewire/flux/zipball/741be2d4526e90b97c7a59e079a2f27ecdce2461", + "reference": "741be2d4526e90b97c7a59e079a2f27ecdce2461", + "shasum": "" + }, + "require": { + "illuminate/console": "^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "illuminate/view": "^10.0|^11.0|^12.0|^13.0", + "laravel/prompts": "^0.1|^0.2|^0.3", + "livewire/livewire": "^3.7.4|^4.0", + "php": "^8.1", + "symfony/console": "^6.0|^7.0|^8.0" + }, + "conflict": { + "livewire/blaze": "<1.0.0-beta.2" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Flux": "Flux\\Flux" + }, + "providers": [ + "Flux\\FluxServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Flux\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "proprietary" + ], + "authors": [ + { + "name": "Caleb Porzio", + "email": "calebporzio@gmail.com" + } + ], + "description": "The official UI component library for Livewire.", + "keywords": [ + "components", + "flux", + "laravel", + "livewire", + "ui" + ], + "support": { + "issues": "https://github.com/livewire/flux/issues", + "source": "https://github.com/livewire/flux/tree/v2.13.0" + }, + "time": "2026-03-03T03:32:35+00:00" + }, + { + "name": "livewire/livewire", + "version": "v4.2.1", + "source": { + "type": "git", + "url": "https://github.com/livewire/livewire.git", + "reference": "93e972fa42c1b34fff1550093ab94f778d81ea5a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/livewire/livewire/zipball/93e972fa42c1b34fff1550093ab94f778d81ea5a", + "reference": "93e972fa42c1b34fff1550093ab94f778d81ea5a", + "shasum": "" + }, + "require": { + "illuminate/database": "^10.0|^11.0|^12.0|^13.0", + "illuminate/routing": "^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "illuminate/validation": "^10.0|^11.0|^12.0|^13.0", + "laravel/prompts": "^0.1.24|^0.2|^0.3", + "league/mime-type-detection": "^1.9", + "php": "^8.1", + "symfony/console": "^6.0|^7.0|^8.0", + "symfony/http-kernel": "^6.2|^7.0|^8.0" + }, + "require-dev": { + "calebporzio/sushi": "^2.1", + "laravel/framework": "^10.15.0|^11.0|^12.0|^13.0", + "mockery/mockery": "^1.3.1", + "orchestra/testbench": "^8.21.0|^9.0|^10.0|^11.0", + "orchestra/testbench-dusk": "^8.24|^9.1|^10.0|^11.0", + "phpunit/phpunit": "^10.4|^11.5|^12.5", + "psy/psysh": "^0.11.22|^0.12" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Livewire": "Livewire\\Livewire" + }, + "providers": [ + "Livewire\\LivewireServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Livewire\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Caleb Porzio", + "email": "calebporzio@gmail.com" + } + ], + "description": "A front-end framework for Laravel.", + "support": { + "issues": "https://github.com/livewire/livewire/issues", + "source": "https://github.com/livewire/livewire/tree/v4.2.1" + }, + "funding": [ + { + "url": "https://github.com/livewire", + "type": "github" + } + ], + "time": "2026-02-28T00:01:19+00:00" + }, + { + "name": "masmerise/livewire-toaster", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/masmerise/livewire-toaster.git", + "reference": "b05faa72456f40452402b8507b7a584bcb7732e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/masmerise/livewire-toaster/zipball/b05faa72456f40452402b8507b7a584bcb7732e6", + "reference": "b05faa72456f40452402b8507b7a584bcb7732e6", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^11.0 || ^12.0", + "illuminate/http": "^11.0 || ^12.0", + "illuminate/routing": "^11.0 || ^12.0", + "illuminate/support": "^11.0 || ^12.0", + "illuminate/view": "^11.0 || ^12.0", + "livewire/livewire": "^3.0 || ^4.0", + "php": "~8.2 || ~8.3 || ~8.4" + }, + "conflict": { + "stevebauman/unfinalize": "*" + }, + "require-dev": { + "larastan/larastan": "^2.0 || ^3.1", + "laravel/pint": "^1.0", + "orchestra/testbench": "^9.0 || ^10.0", + "phpunit/phpunit": "^10.0 || ^11.5.3" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Toaster": "Masmerise\\Toaster\\Toaster" + }, + "providers": [ + "Masmerise\\Toaster\\ToasterServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Masmerise\\Toaster\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Muhammed Sari", + "email": "support@muhammedsari.me", + "role": "Developer" + } + ], + "description": "Beautiful toast notifications for Laravel / Livewire.", + "homepage": "https://github.com/masmerise/livewire-toaster", + "keywords": [ + "alert", + "laravel", + "livewire", + "toast", + "toaster" + ], + "support": { + "issues": "https://github.com/masmerise/livewire-toaster/issues", + "source": "https://github.com/masmerise/livewire-toaster/tree/2.9.0" + }, + "time": "2026-01-17T08:15:08+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.10.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", + "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 || ^2.0", + "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.10.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2026-01-02T08:56:05+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.11.3", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "6a7e652845bb018c668220c2a545aded8594fbbf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/6a7e652845bb018c668220c2a545aded8594fbbf", + "reference": "6a7e652845bb018c668220c2a545aded8594fbbf", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.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": "^v3.87.1", + "kylekatarnls/multi-tester": "^2.5.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^10.5.53", + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.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://carbonphp.github.io/carbon/", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", + "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": "2026-03-11T17:23:39+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.5", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.5" + }, + "require-dev": { + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "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.5" + }, + "time": "2026-02-23T03:47:12+00:00" + }, + { + "name": "nette/utils", + "version": "v4.1.3", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.5", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", + "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.1-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "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.1.3" + }, + "time": "2026-02-13T03:05:33+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "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.x-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.7.0" + }, + "time": "2025-12-06T11:56:16+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.4.4 || ^8.0.4" + }, + "require-dev": { + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", + "phpstan/phpstan": "^1.12.32", + "phpstan/phpstan-strict-rules": "^1.6.2", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", + "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": "It's 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.4.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": "2026-02-16T23:10:27+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.1.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2025-09-24T15:06:41+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "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.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:41:33+00:00" + }, + { + "name": "pragmarx/google2fa", + "version": "v9.0.0", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa.git", + "reference": "e6bc62dd6ae83acc475f57912e27466019a1f2cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/e6bc62dd6ae83acc475f57912e27466019a1f2cf", + "reference": "e6bc62dd6ae83acc475f57912e27466019a1f2cf", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1.0|^2.0|^3.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^7.5.15|^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PragmaRX\\Google2FA\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" + } + ], + "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "keywords": [ + "2fa", + "Authentication", + "Two Factor Authentication", + "google2fa" + ], + "support": { + "issues": "https://github.com/antonioribeiro/google2fa/issues", + "source": "https://github.com/antonioribeiro/google2fa/tree/v9.0.0" + }, + "time": "2025-09-19T22:51:08+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.21", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/4821fab5b7cd8c49a673a9fd5754dc9162bb9e97", + "reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^8.0 || ^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", + "composer/class-map-generator": "^1.6" + }, + "suggest": { + "composer/class-map-generator": "Improved tab completion performance with better class discovery.", + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "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" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "https://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.21" + }, + "time": "2026-03-06T21:21:28+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.9.2", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "8429c78ca35a09f27565311b98101e2826affde0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.25", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "ergebnis/composer-normalize": "^2.47", + "mockery/mockery": "^1.6", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.6", + "php-mock/php-mock-mockery": "^1.5", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpbench/phpbench": "^1.2.14", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6", + "slevomat/coding-standard": "^8.18", + "squizlabs/php_codesniffer": "^3.13" + }, + "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.9.2" + }, + "time": "2025-12-14T04:43:48+00:00" + }, + { + "name": "spatie/laravel-permission", + "version": "6.24.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-permission.git", + "reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/eefc9d17eba80d023d6bff313f882cb2bcd691a3", + "reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3", + "shasum": "" + }, + "require": { + "illuminate/auth": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/container": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/database": "^8.12|^9.0|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "laravel/passport": "^11.0|^12.0", + "laravel/pint": "^1.0", + "orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0", + "phpunit/phpunit": "^9.4|^10.1|^11.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\Permission\\PermissionServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "6.x-dev", + "dev-master": "6.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Permission\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Permission handling for Laravel 8.0 and up", + "homepage": "https://github.com/spatie/laravel-permission", + "keywords": [ + "acl", + "laravel", + "permission", + "permissions", + "rbac", + "roles", + "security", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-permission/issues", + "source": "https://github.com/spatie/laravel-permission/tree/6.24.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2026-02-09T21:10:03+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", + "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.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-11-12T15:39:26+00:00" + }, + { + "name": "symfony/console", + "version": "v7.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2|^8.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|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.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.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-03-06T14:06:20+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "2e7c52c647b406e2107dd867db424a4dbac91864" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/2e7c52c647b406e2107dd867db424a4dbac91864", + "reference": "2e7c52c647b406e2107dd867db424a4dbac91864", + "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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-17T07:53:42+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-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.6.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/error-handler", + "version": "v7.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8da531f364ddfee53e36092a7eebbbd0b775f6b8", + "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/webpack-encore-bundle": "^1.0|^2.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.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-20T16:42:42+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746", + "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|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0|^8.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.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-05T11:45:34+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "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.6-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.6.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/finder", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0|^8.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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-29T09:40:50+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f94b3e7b7dafd40e666f0c9ff2084133bae41e81", + "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" + }, + "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|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.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.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-03-06T13:15:18+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3b3fcf386c809be990c922e10e4c620d6367cab1", + "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.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/flex": "<2.10", + "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|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4.1|^7.0.1|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.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.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-03-06T16:33:18+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "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|^8.0", + "symfony/mime": "^7.2|^8.0", + "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|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T16:50:00+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1", + "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", + "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": "^5.2|^6.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" + }, + "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.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-03-05T15:24:09+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "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.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-10T14:38:51+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "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.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "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\\Php81\\": "" + }, + "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.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "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.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-08T02:45:35+00:00" + }, + { + "name": "symfony/polyfill-php84", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "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\\Php84\\": "" + }, + "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.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-24T13:30:11+00:00" + }, + { + "name": "symfony/polyfill-php85", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "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\\Php85\\": "" + }, + "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.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-23T16:12:55+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.33.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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "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.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "608476f4604102976d687c483ac63a79ba18cc97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", + "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "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.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-26T15:07:59+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "238d749c56b804b31a9bf3e26519d93b65a60938" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/238d749c56b804b31a9bf3e26519d93b65a60938", + "reference": "238d749c56b804b31a9bf3e26519d93b65a60938", + "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|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T16:50:00+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "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.6-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.6.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T11:30:57+00:00" + }, + { + "name": "symfony/string", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.33", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0|^8.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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-09T09:33:46+00:00" + }, + { + "name": "symfony/translation", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "1888cf064399868af3784b9e043240f1d89d25ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/1888cf064399868af3784b9e043240f1d89d25ce", + "reference": "1888cf064399868af3784b9e043240f1d89d25ce", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5.3|^3.3" + }, + "conflict": { + "nikic/php-parser": "<5.0", + "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": "^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0|^8.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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-17T07:53:42+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-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.6.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T13:41:35+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/7719ce8aba76be93dfe249192f1fbfa52c588e36", + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.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.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-03T23:30:35+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/045321c440ac18347b136c63d2e9bf28a2dc0291", + "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-15T10:53:20+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.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.4.0" + }, + "time": "2025-12-02T11:56:42+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.3", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "955e7815d677a3eaa7075231212f2110983adecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" + }, + "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.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:49:13+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" + } + ], + "packages-dev": [ + { + "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.4", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "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.4" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-08-08T12:00:00+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.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.1.1" + }, + "time": "2025-04-30T06:54:44+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.6", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0|^12.0|^13.0", + "illuminate/contracts": "^10.24|^11.0|^12.0|^13.0", + "illuminate/log": "^10.24|^11.0|^12.0|^13.0", + "illuminate/process": "^10.24|^11.0|^12.0|^13.0", + "illuminate/support": "^10.24|^11.0|^12.0|^13.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0|^8.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.0|^13.0", + "laravel/pint": "^1.13", + "orchestra/testbench-core": "^8.13|^9.17|^10.8|^11.0", + "pestphp/pest": "^2.20|^3.0|^4.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0|^4.0", + "phpstan/phpstan": "^1.12.27", + "symfony/var-dumper": "^6.3|^7.0|^8.0", + "symfony/yaml": "^6.3|^7.0|^8.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": [ + "dev", + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2026-02-09T13:44:54+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "bdec963f53172c5e36330f3a400604c69bf02d39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/bdec963f53172c5e36330f3a400604c69bf02d39", + "reference": "bdec963f53172c5e36330f3a400604c69bf02d39", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.94.2", + "illuminate/view": "^12.54.1", + "larastan/larastan": "^3.9.3", + "laravel-zero/framework": "^12.0.5", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.4.0", + "pestphp/pest": "^3.8.6", + "shipfastlabs/agent-detector": "^1.1.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": [ + "dev", + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2026-03-12T15:51:39+00:00" + }, + { + "name": "laravel/sail", + "version": "v1.53.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/sail.git", + "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sail/zipball/e340eaa2bea9b99192570c48ed837155dbf24fbb", + "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0|^8.0", + "symfony/yaml": "^6.0|^7.0|^8.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0", + "phpstan/phpstan": "^2.0" + }, + "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": "2026-02-06T12:16:02+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.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "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.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.9.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", + "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.18.4", + "nunomaduro/termwind": "^2.4.0", + "php": "^8.2.0", + "symfony/console": "^7.4.4 || ^8.0.4" + }, + "conflict": { + "laravel/framework": "<11.48.0 || >=14.0.0", + "phpunit/phpunit": "<11.5.50 || >=14.0.0" + }, + "require-dev": { + "brianium/paratest": "^7.8.5", + "larastan/larastan": "^3.9.2", + "laravel/framework": "^11.48.0 || ^12.52.0", + "laravel/pint": "^1.27.1", + "orchestra/testbench-core": "^9.12.0 || ^10.9.0", + "pestphp/pest": "^3.8.5 || ^4.4.1 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.0.3 || ^9.0.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": "2026-02-17T17:33:08+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.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.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.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.46" + }, + "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.12" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-24T07:01:01+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "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": "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.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-02T13:52:54+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.55", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", + "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.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", + "sebastian/type": "^5.1.3", + "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.55" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2026-02-18T12:37:06+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.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "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.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2026-01-24T09:26:40+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.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "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.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "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.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": "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.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:12:51+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.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "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.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-13T04:42:22+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "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.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:55:48+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.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "58751048de17bae71c5aa0d13cb19d79bca26391" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/58751048de17bae71c5aa0d13cb19d79bca26391", + "reference": "58751048de17bae71c5aa0d13cb19d79bca26391", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.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.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-09T09:33:46+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", + "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.3.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-11-17T20:03:58+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/sk-klinik.my.id/config/app.php b/sk-klinik.my.id/config/app.php new file mode 100644 index 0000000..d95fc20 --- /dev/null +++ b/sk-klinik.my.id/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' => 'Asia/Jakarta', + + /* + |-------------------------------------------------------------------------- + | 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', 'id'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), + + 'faker_locale' => env('APP_FAKER_LOCALE', 'id_ID'), + + /* + |-------------------------------------------------------------------------- + | 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(',', (string) 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/sk-klinik.my.id/config/auth.php b/sk-klinik.my.id/config/auth.php new file mode 100644 index 0000000..d7568ff --- /dev/null +++ b/sk-klinik.my.id/config/auth.php @@ -0,0 +1,117 @@ + [ + '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', 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 number 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/sk-klinik.my.id/config/cache.php b/sk-klinik.my.id/config/cache.php new file mode 100644 index 0000000..b32aead --- /dev/null +++ b/sk-klinik.my.id/config/cache.php @@ -0,0 +1,117 @@ + 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", + | "failover", "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', + ], + + 'failover' => [ + 'driver' => 'failover', + 'stores' => [ + 'database', + 'array', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | 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((string) env('APP_NAME', 'laravel')).'-cache-'), + +]; diff --git a/sk-klinik.my.id/config/database.php b/sk-klinik.my.id/config/database.php new file mode 100644 index 0000000..64709ce --- /dev/null +++ b/sk-klinik.my.id/config/database.php @@ -0,0 +1,184 @@ + 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, + 'transaction_mode' => 'DEFERRED', + ], + + '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([ + (PHP_VERSION_ID >= 80500 ? Mysql::ATTR_SSL_CA : 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([ + (PHP_VERSION_ID >= 80500 ? Mysql::ATTR_SSL_CA : 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' => env('DB_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((string) 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'), + 'max_retries' => env('REDIS_MAX_RETRIES', 3), + 'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'), + 'backoff_base' => env('REDIS_BACKOFF_BASE', 100), + 'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000), + ], + + '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'), + 'max_retries' => env('REDIS_MAX_RETRIES', 3), + 'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'), + 'backoff_base' => env('REDIS_BACKOFF_BASE', 100), + 'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000), + ], + + ], + +]; diff --git a/sk-klinik.my.id/config/filesystems.php b/sk-klinik.my.id/config/filesystems.php new file mode 100644 index 0000000..37d8fca --- /dev/null +++ b/sk-klinik.my.id/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' => rtrim(env('APP_URL', 'http://localhost'), '/').'/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/sk-klinik.my.id/config/fortify.php b/sk-klinik.my.id/config/fortify.php new file mode 100644 index 0000000..ce67e2c --- /dev/null +++ b/sk-klinik.my.id/config/fortify.php @@ -0,0 +1,157 @@ + 'web', + + /* + |-------------------------------------------------------------------------- + | Fortify Password Broker + |-------------------------------------------------------------------------- + | + | Here you may specify which password broker Fortify can use when a user + | is resetting their password. This configured value should match one + | of your password brokers setup in your "auth" configuration file. + | + */ + + 'passwords' => 'users', + + /* + |-------------------------------------------------------------------------- + | Username / Email + |-------------------------------------------------------------------------- + | + | This value defines which model attribute should be considered as your + | application's "username" field. Typically, this might be the email + | address of the users but you are free to change this value here. + | + | Out of the box, Fortify expects forgot password and reset password + | requests to have a field named 'email'. If the application uses + | another name for the field you may define it below as needed. + | + */ + + 'username' => 'email', + + 'email' => 'email', + + /* + |-------------------------------------------------------------------------- + | Lowercase Usernames + |-------------------------------------------------------------------------- + | + | This value defines whether usernames should be lowercased before saving + | them in the database, as some database system string fields are case + | sensitive. You may disable this for your application if necessary. + | + */ + + 'lowercase_usernames' => true, + + /* + |-------------------------------------------------------------------------- + | Home Path + |-------------------------------------------------------------------------- + | + | Here you may configure the path where users will get redirected during + | authentication or password reset when the operations are successful + | and the user is authenticated. You are free to change this value. + | + */ + + 'home' => '/dashboard', + + /* + |-------------------------------------------------------------------------- + | Fortify Routes Prefix / Subdomain + |-------------------------------------------------------------------------- + | + | Here you may specify which prefix Fortify will assign to all the routes + | that it registers with the application. If necessary, you may change + | subdomain under which all of the Fortify routes will be available. + | + */ + + 'prefix' => '', + + 'domain' => null, + + /* + |-------------------------------------------------------------------------- + | Fortify Routes Middleware + |-------------------------------------------------------------------------- + | + | Here you may specify which middleware Fortify will assign to the routes + | that it registers with the application. If necessary, you may change + | these middleware but typically this provided default is preferred. + | + */ + + 'middleware' => ['web'], + + /* + |-------------------------------------------------------------------------- + | Rate Limiting + |-------------------------------------------------------------------------- + | + | By default, Fortify will throttle logins to five requests per minute for + | every email and IP address combination. However, if you would like to + | specify a custom rate limiter to call then you may specify it here. + | + */ + + 'limiters' => [ + 'login' => 'login', + 'two-factor' => 'two-factor', + ], + + /* + |-------------------------------------------------------------------------- + | Register View Routes + |-------------------------------------------------------------------------- + | + | Here you may specify if the routes returning views should be disabled as + | you may not need them when building your own application. This may be + | especially true if you're writing a custom single-page application. + | + */ + + 'views' => true, + + /* + |-------------------------------------------------------------------------- + | Features + |-------------------------------------------------------------------------- + | + | Some of the Fortify features are optional. You may disable the features + | by removing them from this array. You're free to only remove some of + | these features, or you can even remove all of these if you need to. + | + */ + + 'features' => [ + Features::registration(), + Features::resetPasswords(), + Features::emailVerification(), + Features::twoFactorAuthentication([ + 'confirm' => true, + 'confirmPassword' => true, + // 'window' => 0 + ]), + ], + +]; diff --git a/sk-klinik.my.id/config/logging.php b/sk-klinik.my.id/config/logging.php new file mode 100644 index 0000000..9e998a4 --- /dev/null +++ b/sk-klinik.my.id/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(',', (string) 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/sk-klinik.my.id/config/mail.php b/sk-klinik.my.id/config/mail.php new file mode 100644 index 0000000..e32e88d --- /dev/null +++ b/sk-klinik.my.id/config/mail.php @@ -0,0 +1,118 @@ + 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((string) 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', + ], + 'retry_after' => 60, + ], + + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'ses', + 'postmark', + ], + 'retry_after' => 60, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | 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', env('APP_NAME', 'Laravel')), + ], + +]; diff --git a/sk-klinik.my.id/config/permission.php b/sk-klinik.my.id/config/permission.php new file mode 100644 index 0000000..f39f6b5 --- /dev/null +++ b/sk-klinik.my.id/config/permission.php @@ -0,0 +1,202 @@ + [ + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * Eloquent model should be used to retrieve your permissions. Of course, it + * is often just the "Permission" model but you may use whatever you like. + * + * The model you want to use as a Permission model needs to implement the + * `Spatie\Permission\Contracts\Permission` contract. + */ + + 'permission' => Spatie\Permission\Models\Permission::class, + + /* + * When using the "HasRoles" trait from this package, we need to know which + * Eloquent model should be used to retrieve your roles. Of course, it + * is often just the "Role" model but you may use whatever you like. + * + * The model you want to use as a Role model needs to implement the + * `Spatie\Permission\Contracts\Role` contract. + */ + + 'role' => Spatie\Permission\Models\Role::class, + + ], + + 'table_names' => [ + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'roles' => 'roles', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your permissions. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'permissions' => 'permissions', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your models permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_permissions' => 'model_has_permissions', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your models roles. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_roles' => 'model_has_roles', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'role_has_permissions' => 'role_has_permissions', + ], + + 'column_names' => [ + /* + * Change this if you want to name the related pivots other than defaults + */ + 'role_pivot_key' => null, // default 'role_id', + 'permission_pivot_key' => null, // default 'permission_id', + + /* + * Change this if you want to name the related model primary key other than + * `model_id`. + * + * For example, this would be nice if your primary keys are all UUIDs. In + * that case, name this `model_uuid`. + */ + + 'model_morph_key' => 'model_id', + + /* + * Change this if you want to use the teams feature and your related model's + * foreign key is other than `team_id`. + */ + + 'team_foreign_key' => 'team_id', + ], + + /* + * When set to true, the method for checking permissions will be registered on the gate. + * Set this to false if you want to implement custom logic for checking permissions. + */ + + 'register_permission_check_method' => true, + + /* + * When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered + * this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated + * NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it. + */ + 'register_octane_reset_listener' => false, + + /* + * Events will fire when a role or permission is assigned/unassigned: + * \Spatie\Permission\Events\RoleAttached + * \Spatie\Permission\Events\RoleDetached + * \Spatie\Permission\Events\PermissionAttached + * \Spatie\Permission\Events\PermissionDetached + * + * To enable, set to true, and then create listeners to watch these events. + */ + 'events_enabled' => false, + + /* + * Teams Feature. + * When set to true the package implements teams using the 'team_foreign_key'. + * If you want the migrations to register the 'team_foreign_key', you must + * set this to true before doing the migration. + * If you already did the migration then you must make a new migration to also + * add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions' + * (view the latest version of this package's migration file) + */ + + 'teams' => false, + + /* + * The class to use to resolve the permissions team id + */ + 'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class, + + /* + * Passport Client Credentials Grant + * When set to true the package will use Passports Client to check permissions + */ + + 'use_passport_client_credentials' => false, + + /* + * When set to true, the required permission names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_permission_in_exception' => false, + + /* + * When set to true, the required role names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_role_in_exception' => false, + + /* + * By default wildcard permission lookups are disabled. + * See documentation to understand supported syntax. + */ + + 'enable_wildcard_permission' => false, + + /* + * The class to use for interpreting wildcard permissions. + * If you need to modify delimiters, override the class and specify its name here. + */ + // 'wildcard_permission' => Spatie\Permission\WildcardPermission::class, + + /* Cache-specific settings */ + + 'cache' => [ + + /* + * By default all permissions are cached for 24 hours to speed up performance. + * When permissions or roles are updated the cache is flushed automatically. + */ + + 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + + /* + * The cache key used to store all permissions. + */ + + 'key' => 'spatie.permission.cache', + + /* + * You may optionally indicate a specific cache driver to use for permission and + * role caching using any of the `store` drivers listed in the cache.php config + * file. Using 'default' here means to use the `default` set in cache.php. + */ + + 'store' => 'default', + ], +]; diff --git a/sk-klinik.my.id/config/queue.php b/sk-klinik.my.id/config/queue.php new file mode 100644 index 0000000..79c2c0a --- /dev/null +++ b/sk-klinik.my.id/config/queue.php @@ -0,0 +1,129 @@ + 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", + | "deferred", "background", "failover", "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, + ], + + 'deferred' => [ + 'driver' => 'deferred', + ], + + 'background' => [ + 'driver' => 'background', + ], + + 'failover' => [ + 'driver' => 'failover', + 'connections' => [ + 'database', + 'deferred', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | 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/sk-klinik.my.id/config/services.php b/sk-klinik.my.id/config/services.php new file mode 100644 index 0000000..6a90eb8 --- /dev/null +++ b/sk-klinik.my.id/config/services.php @@ -0,0 +1,38 @@ + [ + 'key' => env('POSTMARK_API_KEY'), + ], + + 'resend' => [ + 'key' => env('RESEND_API_KEY'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'slack' => [ + 'notifications' => [ + 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), + 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), + ], + ], + +]; diff --git a/sk-klinik.my.id/config/session.php b/sk-klinik.my.id/config/session.php new file mode 100644 index 0000000..fd927b4 --- /dev/null +++ b/sk-klinik.my.id/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: "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((string) 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 without 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/sk-klinik.my.id/config/toaster.php b/sk-klinik.my.id/config/toaster.php new file mode 100644 index 0000000..9abb774 --- /dev/null +++ b/sk-klinik.my.id/config/toaster.php @@ -0,0 +1,61 @@ + true, + + /** + * The vertical alignment of the toast container. + * + * Supported: "bottom", "middle" or "top" + */ + 'alignment' => 'top', + + /** + * Allow users to close toast messages prematurely. + * + * Supported: true | false + */ + 'closeable' => true, + + /** + * The on-screen duration of each toast. + * + * Minimum: 3000 (in milliseconds) + */ + 'duration' => 3000, + + /** + * The horizontal position of each toast. + * + * Supported: "center", "left" or "right" + */ + 'position' => 'right', + + /** + * New toasts immediately replace similar ones, ensuring only one toast of a kind is visible at any time. + * Takes precedence over the "suppress" option. + * + * Supported: true | false + */ + 'replace' => false, + + /** + * Prevent the display of duplicate toast messages. + * + * Supported: true | false + */ + 'suppress' => false, + + /** + * Whether messages passed as translation keys should be translated automatically. + * + * Supported: true | false + */ + 'translate' => true, +]; diff --git a/sk-klinik.my.id/database - copy b/sk-klinik.my.id/database - copy new file mode 100644 index 0000000000000000000000000000000000000000..f3a14baf24790360a96d695857b0f9cfe5399102 GIT binary patch literal 208896 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 literal 0 HcmV?d00001 diff --git a/sk-klinik.my.id/database/.gitignore b/sk-klinik.my.id/database/.gitignore new file mode 100644 index 0000000..9b19b93 --- /dev/null +++ b/sk-klinik.my.id/database/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/sk-klinik.my.id/database/factories/UserFactory.php b/sk-klinik.my.id/database/factories/UserFactory.php new file mode 100644 index 0000000..98825c8 --- /dev/null +++ b/sk-klinik.my.id/database/factories/UserFactory.php @@ -0,0 +1,60 @@ + + */ +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), + 'two_factor_secret' => null, + 'two_factor_recovery_codes' => null, + 'two_factor_confirmed_at' => null, + ]; + } + + /** + * Indicate that the model's email address should be unverified. + */ + public function unverified(): static + { + return $this->state(fn (array $attributes) => [ + 'email_verified_at' => null, + ]); + } + + /** + * Indicate that the model has two-factor authentication configured. + */ + public function withTwoFactor(): static + { + return $this->state(fn (array $attributes) => [ + 'two_factor_secret' => encrypt('secret'), + 'two_factor_recovery_codes' => encrypt(json_encode(['recovery-code-1'])), + 'two_factor_confirmed_at' => now(), + ]); + } +} diff --git a/sk-klinik.my.id/database/migrations/0001_01_01_000000_create_users_table.php b/sk-klinik.my.id/database/migrations/0001_01_01_000000_create_users_table.php new file mode 100644 index 0000000..05fb5d9 --- /dev/null +++ b/sk-klinik.my.id/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/sk-klinik.my.id/database/migrations/0001_01_01_000001_create_cache_table.php b/sk-klinik.my.id/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..ed758bd --- /dev/null +++ b/sk-klinik.my.id/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration')->index(); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/0001_01_01_000002_create_jobs_table.php b/sk-klinik.my.id/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..967fbf5 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,59 @@ +id(); + $table->string('queue'); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + + $table->index(['queue', 'reserved_at', 'available_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/sk-klinik.my.id/database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php b/sk-klinik.my.id/database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php new file mode 100644 index 0000000..187d974 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php @@ -0,0 +1,34 @@ +text('two_factor_secret')->after('password')->nullable(); + $table->text('two_factor_recovery_codes')->after('two_factor_secret')->nullable(); + $table->timestamp('two_factor_confirmed_at')->after('two_factor_recovery_codes')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn([ + 'two_factor_secret', + 'two_factor_recovery_codes', + 'two_factor_confirmed_at', + ]); + }); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_03_14_031324_create_permission_tables.php b/sk-klinik.my.id/database/migrations/2026_03_14_031324_create_permission_tables.php new file mode 100644 index 0000000..66ce1f9 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_03_14_031324_create_permission_tables.php @@ -0,0 +1,134 @@ +engine('InnoDB'); + $table->bigIncrements('id'); // permission id + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + + $table->unique(['name', 'guard_name']); + }); + + Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) { + // $table->engine('InnoDB'); + $table->bigIncrements('id'); // role id + if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing + $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); + $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); + } + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + if ($teams || config('permission.testing')) { + $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); + } else { + $table->unique(['name', 'guard_name']); + } + }); + + Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) { + $table->unsignedBigInteger($pivotPermission); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } else { + $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } + + }); + + Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) { + $table->unsignedBigInteger($pivotRole); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } else { + $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } + }); + + Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) { + $table->unsignedBigInteger($pivotPermission); + $table->unsignedBigInteger($pivotRole); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + + $table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary'); + }); + + app('cache') + ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) + ->forget(config('permission.cache.key')); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $tableNames = config('permission.table_names'); + + throw_if(empty($tableNames), Exception::class, 'Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + + Schema::drop($tableNames['role_has_permissions']); + Schema::drop($tableNames['model_has_roles']); + Schema::drop($tableNames['model_has_permissions']); + Schema::drop($tableNames['roles']); + Schema::drop($tableNames['permissions']); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_03_14_031532_create_settings_table.php b/sk-klinik.my.id/database/migrations/2026_03_14_031532_create_settings_table.php new file mode 100644 index 0000000..ce3b578 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_03_14_031532_create_settings_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('key')->unique(); + $table->text('value')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('settings'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_03_14_143718_create_patients_table.php b/sk-klinik.my.id/database/migrations/2026_03_14_143718_create_patients_table.php new file mode 100644 index 0000000..8bffeb3 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_03_14_143718_create_patients_table.php @@ -0,0 +1,48 @@ +id(); + $table->foreignId('user_id')->constrained()->onDelete('cascade'); + $table->string('nik', 16)->unique(); + $table->string('place_of_birth'); + $table->date('date_of_birth'); + + $table->enum('gender', ['L', 'P']); + $table->enum('blood_type', ['A', 'B', 'AB', 'O', '-'])->nullable(); + + $table->string('phone'); + $table->text('address'); + + // Kontak Darurat + $table->string('emergency_contact_name')->nullable(); + $table->string('emergency_contact_phone')->nullable(); + $table->string('emergency_contact_relation')->nullable(); + + $table->string('insurance_type')->default('Umum'); // Umum, BPJS, Asuransi Swasta + $table->string('insurance_number')->nullable(); + + //$table->text('allergies')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('patients'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_03_15_054112_create_news_table.php b/sk-klinik.my.id/database/migrations/2026_03_15_054112_create_news_table.php new file mode 100644 index 0000000..b9b5825 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_03_15_054112_create_news_table.php @@ -0,0 +1,38 @@ +id(); + $table->foreignId('category_id') + ->nullable() + ->constrained() + ->onDelete('set null'); + $table->string('title'); + $table->string('slug')->unique(); + $table->string('image')->nullable(); // Path untuk thumbnail berita + $table->longText('content'); // Isi berita (bisa HTML dari Editor) + $table->foreignId('user_id')->constrained(); // Siapa admin yang menulis + $table->boolean('is_published')->default(false); + $table->integer('view_count')->default(0); // Untuk statistik berita populer + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('news'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_03_15_055324_create_categories_table.php b/sk-klinik.my.id/database/migrations/2026_03_15_055324_create_categories_table.php new file mode 100644 index 0000000..4fe1bd3 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_03_15_055324_create_categories_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('name'); + $table->string('slug')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('categories'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_03_15_112730_create_appointments_table.php b/sk-klinik.my.id/database/migrations/2026_03_15_112730_create_appointments_table.php new file mode 100644 index 0000000..33f1983 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_03_15_112730_create_appointments_table.php @@ -0,0 +1,50 @@ +id(); + + // Relasi Utama + $table->foreignId('patient_id')->constrained('users')->onDelete('cascade'); + + $table->foreignId('doctor_id')->nullable()->constrained('doctors')->onDelete('set null'); + + $table->foreignId('service_category_id')->constrained('service_categories'); + + // Data Antrean + $table->date('appointment_date'); + $table->integer('queue_number'); + + // Status & Keterangan + $table->enum('status', ['waiting', 'calling', 'finished', 'cancelled','skipped'])->default('waiting'); + $table->text('notes')->nullable(); // Keluhan awal pasien + + // Audit Trail + $table->foreignId('created_by')->nullable()->constrained('users'); // Admin atau Pasien + + $table->timestamps(); + //$table->softDeletes(); // Disarankan agar data tidak benar-benar hilang jika dihapus + + // Constraint Unik + $table->unique(['patient_id', 'appointment_date'], 'one_appointment_per_day'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('appointments'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_04_03_044049_create_doctors_table.php b/sk-klinik.my.id/database/migrations/2026_04_03_044049_create_doctors_table.php new file mode 100644 index 0000000..27da4dd --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_04_03_044049_create_doctors_table.php @@ -0,0 +1,35 @@ +id(); + + $table->string('name'); + $table->string('specialization'); // Spesialis + $table->string('phone'); + $table->string('email')->nullable(); + $table->text('schedule')->nullable(); // Jadwal praktik + $table->string('photo')->nullable(); // Foto dokter + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('doctors'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_04_03_050708_create_service_categories_table.php b/sk-klinik.my.id/database/migrations/2026_04_03_050708_create_service_categories_table.php new file mode 100644 index 0000000..a0a20fe --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_04_03_050708_create_service_categories_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('service_categories'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_04_03_050731_create_services_table.php b/sk-klinik.my.id/database/migrations/2026_04_03_050731_create_services_table.php new file mode 100644 index 0000000..dd94946 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_04_03_050731_create_services_table.php @@ -0,0 +1,36 @@ +id(); + + $table->foreignId('category_id') + ->constrained('service_categories') + ->cascadeOnDelete(); + + $table->string('name'); + $table->text('description')->nullable(); + $table->json('photo')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('services'); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_07_11_071004_add_medical_record_number_to_patients_table.php b/sk-klinik.my.id/database/migrations/2026_07_11_071004_add_medical_record_number_to_patients_table.php new file mode 100644 index 0000000..934e87a --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_07_11_071004_add_medical_record_number_to_patients_table.php @@ -0,0 +1,28 @@ +string('medical_record_number', 20)->nullable()->unique()->after('id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('patients', function (Blueprint $table) { + $table->dropColumn('medical_record_number'); + }); + } +}; diff --git a/sk-klinik.my.id/database/migrations/2026_07_11_080037_create_medical_records_table.php b/sk-klinik.my.id/database/migrations/2026_07_11_080037_create_medical_records_table.php new file mode 100644 index 0000000..2881ca6 --- /dev/null +++ b/sk-klinik.my.id/database/migrations/2026_07_11_080037_create_medical_records_table.php @@ -0,0 +1,36 @@ +id(); + $table->foreignId('patient_id')->constrained('patients')->onDelete('cascade'); + $table->foreignId('appointment_id')->nullable()->constrained('appointments')->onDelete('set null'); + $table->foreignId('doctor_id')->nullable()->constrained('doctors')->onDelete('set null'); + + $table->text('symptoms'); // Keluhan Utama / Anamnesis + $table->text('diagnosis'); // Hasil Diagnosa Dokter + $table->text('treatment')->nullable(); // Tindakan / Resep Obat + $table->text('notes')->nullable(); // Catatan Tambahan Dokter + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('medical_records'); + } +}; diff --git a/sk-klinik.my.id/database/seeders/DatabaseSeeder.php b/sk-klinik.my.id/database/seeders/DatabaseSeeder.php new file mode 100644 index 0000000..ff8e920 --- /dev/null +++ b/sk-klinik.my.id/database/seeders/DatabaseSeeder.php @@ -0,0 +1,32 @@ +create(); + + // User::factory()->create([ + // 'name' => 'Test User', + // 'email' => 'test@example.com', + // ]); + + $this->call([ + SettingSeeder::class, + RoleSeeder::class, + PermissionSeeder::class, + UserSeeder::class, + ServiceCategorySeeder::class, + ServiceSeeder::class, + ]); + } +} diff --git a/sk-klinik.my.id/database/seeders/PermissionSeeder.php b/sk-klinik.my.id/database/seeders/PermissionSeeder.php new file mode 100644 index 0000000..88c34eb --- /dev/null +++ b/sk-klinik.my.id/database/seeders/PermissionSeeder.php @@ -0,0 +1,60 @@ +forgetCachedPermissions(); + + $permissions = [ + // Dashboard + 'view-dashboard', + + // User Management + 'user-list', + 'user-manage', + 'role-manage', + 'permission-manage', + + // Patient Management + 'patient-list', + 'patient-manage', + 'patient-print', + + // News & Category + 'news-list', + 'news-manage', + 'category-manage', + + // Operations + 'antrean-manage', + 'doctor-manage', + 'service-manage', + + // System Settings (Pastikan pakai 's') + 'settings-manage', + ]; + + foreach ($permissions as $permission) { + Permission::firstOrCreate([ + 'name' => $permission, + 'guard_name' => 'web' + ]); + } + + // Setup Role Admin + $adminRole = Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']); + $adminRole->syncPermissions(Permission::all()); + + // Setup Role Lainnya + Role::firstOrCreate(['name' => 'patient', 'guard_name' => 'web']); + Role::firstOrCreate(['name' => 'guest', 'guard_name' => 'web']); + } +} diff --git a/sk-klinik.my.id/database/seeders/RoleSeeder.php b/sk-klinik.my.id/database/seeders/RoleSeeder.php new file mode 100644 index 0000000..1734d7c --- /dev/null +++ b/sk-klinik.my.id/database/seeders/RoleSeeder.php @@ -0,0 +1,28 @@ +forgetCachedPermissions(); + + // Buat Role + Role::create(['name' => 'admin']); + Role::create(['name' => 'guest']); + Role::create(['name' => 'patient']); + + // Tambahan jika perlu untuk klinik ke depannya + // Role::create(['name' => 'dokter']); + // Role::create(['name' => 'resepsionis']); + } +} diff --git a/sk-klinik.my.id/database/seeders/ServiceCategorySeeder.php b/sk-klinik.my.id/database/seeders/ServiceCategorySeeder.php new file mode 100644 index 0000000..a0226c8 --- /dev/null +++ b/sk-klinik.my.id/database/seeders/ServiceCategorySeeder.php @@ -0,0 +1,29 @@ + $category + ]); + } + } +} diff --git a/sk-klinik.my.id/database/seeders/ServiceSeeder.php b/sk-klinik.my.id/database/seeders/ServiceSeeder.php new file mode 100644 index 0000000..659d379 --- /dev/null +++ b/sk-klinik.my.id/database/seeders/ServiceSeeder.php @@ -0,0 +1,72 @@ +first(); + $bedah = ServiceCategory::where('name', 'Bedah Minor')->first(); + $penunjang = ServiceCategory::where('name', 'Penunjang Medis')->first(); + $kandungan = ServiceCategory::where('name', 'Kebidanan & Kandungan')->first(); + + // ===================== + // 1. Pelayanan Medis Umum + // ===================== + $this->insertServices($medis, [ + 'Unit Gawat Darurat (UGD) 24 Jam', + 'Poliklinik Dokter Umum', + 'Rawat Inap', + ]); + + // ===================== + // 2. Bedah Minor + // ===================== + $this->insertServices($bedah, [ + 'Cirkumsisi (Khitan)', + 'Abses (Bisul)', + 'Clavus (Kapalen)', + 'Ganglioma (Uci-Uci)', + 'Peringual (Cantengan)', + ]); + + // ===================== + // 3. Penunjang Medis + // ===================== + $this->insertServices($penunjang, [ + 'Laboratorium', + 'Farmasi', + 'ECG (Rekam Jantung)', + 'USG Kandungan', + ]); + + // ===================== + // 4. Kebidanan & Kandungan + // ===================== + $this->insertServices($kandungan, [ + 'Pemeriksaan Kehamilan', + 'USG Kehamilan', + 'Persalinan Normal', + 'Perawatan Ibu Nifas & Bayi Baru Lahir', + 'KB (Suntik, IUD, Pil, & Implan)', + ]); + } + + private function insertServices($category, $services) + { + if (!$category) return; + + foreach ($services as $service) { + Service::firstOrCreate([ + 'name' => $service, + 'category_id' => $category->id + ]); + } + } +} diff --git a/sk-klinik.my.id/database/seeders/SettingSeeder.php b/sk-klinik.my.id/database/seeders/SettingSeeder.php new file mode 100644 index 0000000..1aa4946 --- /dev/null +++ b/sk-klinik.my.id/database/seeders/SettingSeeder.php @@ -0,0 +1,42 @@ + 'site_name', 'value' => 'Klinik Rawat Inap Sahabat Keluarga'], + ['key' => 'site_description', 'value' => 'Sistem Informasi Klinik Terintegrasi dan Pelayanan Pasien.'], + ['key' => 'meta_keywords', 'value' => 'klinik, rekam medis, dokter, pendaftaran pasien online'], + + // Branding + ['key' => 'accent_color', 'value' => 'blue'], + ['key' => 'base_color', 'value' => 'gray'], + + // Kontak & Lokasi (Penting untuk Klinik) + ['key' => 'clinic_address', 'value' => 'Jl. Raya Kedondong, Sanggrahan, Kedondong, Kec. Bagor, Kabupaten Nganjuk, Jawa Timur 64461'], + ['key' => 'clinic_phone', 'value' => '0822-3039-8955'], + ['key' => 'clinic_email', 'value' => ''], + ['key' => 'clinic_latitude', 'value' => '-7.5861452'], + ['key' => 'clinic_longitude', 'value' => '111.8812542'], + + // Operasional + ['key' => 'maintenance_mode', 'value' => 'false'], + ['key' => 'registration_open', 'value' => 'true'], + ]; + + foreach ($settings as $setting) { + Setting::updateOrCreate(['key' => $setting['key']], ['value' => $setting['value']]); + } + } +} diff --git a/sk-klinik.my.id/database/seeders/UserSeeder.php b/sk-klinik.my.id/database/seeders/UserSeeder.php new file mode 100644 index 0000000..62954af --- /dev/null +++ b/sk-klinik.my.id/database/seeders/UserSeeder.php @@ -0,0 +1,35 @@ + 'Admin Klinik', + 'email' => 'admin@klinik.com', + 'password' => Hash::make('password123'), + 'email_verified_at' => now(), + ]); + $admin->syncRoles(['admin']); + + // Buat User Guest + $guest = User::create([ + 'name' => 'Pasien Contoh', + 'email' => 'guest@gmail.com', + 'password' => Hash::make('password123'), + 'email_verified_at' => now(), + ]); + $guest->syncRoles('guest'); + } +} diff --git a/sk-klinik.my.id/lang/id.json b/sk-klinik.my.id/lang/id.json new file mode 100644 index 0000000..fdbe465 --- /dev/null +++ b/sk-klinik.my.id/lang/id.json @@ -0,0 +1,336 @@ +{ + "(and :count more error)": "(dan :count kesalahan lainnya)", + "(and :count more errors)": "(dan :count kesalahan lainnya)|(dan :count kesalahan lainnya)|(dan :count kesalahan lainnya)", + "2FA Recovery Codes": "2FA Kode Pemulihan", + "A decryption key is required.": "Kunci dekripsi diperlukan.", + "A new verification link has been sent to the email address you provided during registration.": "Tautan verifikasi baru telah dikirim ke alamat surel yang Anda berikan saat pendaftaran.", + "A new verification link has been sent to your email address.": "Tautan verifikasi baru telah dikirim ke alamat email Anda.", + "A reset link will be sent if the account exists.": "Tautan reset akan dikirim jika ada akun.", + "A Timeout Occurred": "Terjadi Timeout", + "Accept": "Menerima", + "Accepted": "Diterima", + "Action": "Aksi", + "Actions": "Aksi", + "Add": "Tambah", + "Add :name": "Tambahkan :name", + "Admin": "Admin", + "Agree": "Setuju", + "All rights reserved.": "Hak Cipta Dilindungi.", + "Already have an account?": "Sudah punya akun?", + "Already Reported": "Sudah dilaporkan", + "Appearance": "Tampilan", + "Appearance Settings": "Pengaturan Tampilan", + "Archive": "Arsip", + "Are you sure you want to delete your account?": "Apakah Anda yakin ingin menghapus akun Anda?", + "Assign": "Menetapkan", + "Associate": "Rekan", + "Attach": "Lampirkan", + "Authentication Code": "Kode otentikasi", + "Back": "Kembali", + "Bad Gateway": "Gateway buruk", + "Bad Request": "Permintaan yang buruk", + "Bandwidth Limit Exceeded": "Batas Bandwidth terlampaui", + "Browse": "Jelajahi", + "Cancel": "Batal", + "Choose": "Pilih", + "Choose :name": "Pilih :name", + "Choose File": "Pilih Berkas", + "Choose Image": "Pilih Gambar", + "Click here to re-send the verification email.": "Klik disini untuk mengirim ulang verifikasi email.", + "Click to copy": "Klik untuk menyalin", + "Client Closed Request": "Permintaan ditutup klien", + "Close": "Menutup", + "Collapse": "Runtuh", + "Collapse All": "Ciutkan Semua", + "Comment": "Komentar", + "Confirm": "Konfirmasi", + "Confirm Password": "Konfirmasi Kata Sandi", + "Confirm password": "Konfirmasi Kata Sandi", + "Conflict": "Konflik", + "Connect": "Menghubung", + "Connection Closed Without Response": "Koneksi Ditutup Tanpa Respon", + "Connection Timed Out": "Waktu koneksi berakhir", + "Continue": "Melanjutkan", + "Create": "Buat", + "Create :name": "Buat :name", + "Create account": "Buat akun", + "Create an account": "Buat akun", + "Created": "Dibuat", + "Current password": "Kata sandi saat ini", + "Dark": "Gelap", + "Dashboard": "Dasbor", + "Delete": "Hapus", + "Delete :name": "Hapus :name", + "Delete account": "Hapus akun", + "Delete your account and all of its resources": "Hapus akun Anda dan semua sumber dayanya", + "Detach": "Melepaskan", + "Details": "Detail", + "Disable": "Matikan", + "Disable 2FA": "Nonaktifkan 2FA", + "Disabled": "Dengan disabilitas", + "Discard": "Membuang", + "Documentation": "Dokumentasi", + "Don't have an account?": "Tidak punya akun?", + "Done": "Selesai", + "Down": "Turun", + "Duplicate": "Duplikat", + "Duplicate :name": "Duplikat: nama", + "Each recovery code can be used once to access your account and will be removed after use. If you need more, click Regenerate Codes above.": "Setiap kode pemulihan dapat digunakan sekali untuk mengakses akun Anda dan akan dihapus setelah digunakan. Jika Anda membutuhkan lebih banyak, klik Kode Regenerate di atas.", + "Edit": "Sunting", + "Edit :name": "Sunting :name", + "Email": "Surel", + "Email Address": "Alamat Surel", + "Email address": "Alamat email", + "Email password reset link": "Tautan Reset Kata Sandi Email", + "Email verification": "Email verification", + "Enable": "Nyalakan", + "Enable 2FA": "Aktifkan 2FA", + "Enable Two-Factor Authentication": "Aktifkan otentikasi dua faktor", + "Enabled": "Diaktifkan", + "Encrypted environment file already exists.": "Enkripsi file environment sudah ada.", + "Encrypted environment file not found.": "Enkripsi file environment tidak ditemukan.", + "Ensure your account is using a long, random password to stay secure": "Pastikan akun Anda menggunakan kata sandi panjang dan acak agar tetap aman", + "Enter the 6-digit code from your authenticator app.": "Masukkan kode 6 digit dari aplikasi Authenticator Anda.", + "Enter the authentication code provided by your authenticator application.": "Masukkan kode otentikasi yang disediakan oleh aplikasi authenticator Anda.", + "Enter your details below to create your account": "Masukkan detail Anda di bawah ini untuk membuat akun Anda", + "Enter your email and password below to log in": "Masukkan email dan kata sandi Anda di bawah ini untuk masuk", + "Enter your email to receive a password reset link": "Masukkan email Anda untuk menerima tautan reset kata sandi", + "Environment file already exists.": "File environment sudah ada.", + "Environment file not found.": "file environment tidak ditemukan.", + "errors": "kesalahan", + "Expand": "Memperluas", + "Expand All": "Melebarkan semua", + "Expectation Failed": "Ekspetasi gagal", + "Explanation": "Penjelasan", + "Export": "Ekspor", + "Export :name": "Export :name", + "Failed Dependency": "Dependensi gagal", + "File": "Mengajukan", + "Files": "File", + "Forbidden": "Dilarang", + "Forgot password": "Lupa kata sandi", + "Forgot your password?": "Lupa kata sandi Anda?", + "Found": "Ditemukan", + "Full name": "Nama lengkap", + "Gateway Timeout": "Gateway waktu habis", + "Go Home": "Ke Halaman Utama", + "Go to page :page": "Ke halaman :page", + "Gone": "Hilang", + "Hello!": "Halo!", + "Hide": "Bersembunyi", + "Hide :name": "Sembunyikan :name", + "Hide Recovery Codes": "Sembunyikan Kode Pemulihan", + "Home": "Rumah", + "HTTP Version Not Supported": "Versi HTTP tidak mendukung", + "I'm a teapot": "Saya teko", + "If you did not create an account, no further action is required.": "Jika Anda tidak membuat akun, Anda tidak perlu melakukan apapun.", + "If you did not request a password reset, no further action is required.": "Jika Anda tidak meminta pengaturan ulang kata sandi, Anda tidak perlu melakukan apapun.", + "If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": "Jika Anda mengalami kesulitan mengklik tombol \":actionText\", salin dan tempel URL di bawah\nke browser web Anda:", + "IM Used": "IM Digunakan", + "Image": "Gambar", + "Impersonate": "Penyamaran", + "Impersonation": "Peniruan", + "Import": "Impor", + "Import :name": "Impor :name", + "Insufficient Storage": "Penyimpanan tidak cukup", + "Internal Server Error": "Kesalahan dari dalam server", + "Introduction": "Perkenalan", + "Invalid filename.": "Nama file tidak valid.", + "Invalid JSON was returned from the route.": "JSON yang tidak valid dikembalikan dari rute.", + "Invalid SSL Certificate": "Sertifikat SSL tidak sah", + "length": "panjang", + "Length Required": "Panjang diperlukan", + "Light": "Terang", + "Like": "Menyukai", + "Load": "Memuat", + "Localize": "Melokalisir", + "Location": "Lokasi", + "Locked": "Terkunci", + "Log In": "Masuk", + "Log in": "Masuk", + "log in": "Masuk", + "Log in to your account": "Masuk ke akun Anda", + "Log Out": "Keluar", + "Log out": "Keluar", + "Login": "Masuk", + "login using a recovery code": "Masuk menggunakan kode pemulihan", + "login using an authentication code": "Masuk menggunakan kode otentikasi", + "Logout": "Keluar", + "Loop Detected": "Terdeteksi perulangan", + "Maintenance Mode": "Mode pemeliharaan", + "Manage your profile and account settings": "Kelola Profil dan Pengaturan Akun Anda", + "Manage your two-factor authentication settings": "Kelola Pengaturan Otentikasi Dua Faktor Anda", + "Method Not Allowed": "Metode tidak diizinkan", + "Misdirected Request": "Permintaan salah arah", + "Moved Permanently": "Pengalihan permanen", + "Multi-Status": "Status ganda", + "Multiple Choices": "Pilihan ganda", + "Name": "Nama", + "Network Authentication Required": "Otentikasi jaringan diperlukan", + "Network Connect Timeout Error": "Network Connect Timeout gagal", + "Network Read Timeout Error": "Network Read Timeout gagal", + "New": "Baru", + "New :name": "Baru :name", + "New password": "Kata sandi baru", + "No": "Tidak", + "No Content": "Tidak ada konten", + "Non-Authoritative Information": "Informasi Non-Otoritatif", + "Not Acceptable": "Tidak dapat diterima", + "Not Extended": "Tidak diperpanjang", + "Not Found": "Tidak ditemukan", + "Not Implemented": "Tidak dilaksanakan", + "Not Modified": "Tidak dimodifikasi", + "of": "dari", + "OK": "OKE", + "Once your account is deleted, all of its resources and data will also be permanently deleted. Please confirm you would like to permanently delete your account.": "Setelah akun Anda dihapus, semua sumber daya dan datanya juga akan dihapus secara permanen. Harap konfirmasi Anda ingin menghapus akun Anda secara permanen.", + "Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.": "Setelah akun dihapus, seluruh sumber dan datanya akan dihapus secara permanen. Harap isi kata sandi anda untuk mengkonfirmasi bahwa anda ingin menghapus akun milik Anda secara permanen.", + "Open": "Membuka", + "Open in a current window": "Buka di jendela saat ini", + "Open in a new window": "Buka di jendela baru", + "Open in a parent frame": "Buka di bingkai induk", + "Open in the topmost frame": "Buka di bingkai paling atas", + "Open on the website": "Buka di situs web", + "or you can": "atau Anda bisa", + "or, enter the code manually": "Atau, masukkan kode secara manual", + "Or, return to": "Atau, kembali ke", + "Origin Is Unreachable": "Asal tidak terjangkau", + "Page Expired": "Halaman Kadaluwarsa", + "Pagination Navigation": "Navigasi Paginasi", + "Partial Content": "Konten parsial", + "Password": "Kata Sandi", + "Password Settings": "Pengaturan Kata Sandi", + "Payload Too Large": "Payload terlalu besar", + "Payment Required": "Pembayaran Diperlukan", + "Permanent Redirect": "Pengalihan permanen", + "Platform": "Platform", + "Please click the button below to verify your email address.": "Silakan klik tombol di bawah untuk memverifikasi alamat surel Anda.", + "Please confirm access to your account by entering one of your emergency recovery codes.": "Harap konfirmasi akses ke akun Anda dengan memasukkan salah satu kode pemulihan darurat Anda.", + "Please enter your new password below": "Harap masukkan kata sandi baru Anda di bawah ini", + "Please verify your email address by clicking on the link we just emailed to you.": "Harap verifikasi alamat email Anda dengan mengklik tautan yang baru saja kami kirimi email kepada Anda.", + "Precondition Failed": "Prasyarat Gagal", + "Precondition Required": "Prasyarat diperlukan", + "Preview": "Pratinjau", + "Price": "Harga", + "Processing": "Memproses", + "Profile": "Profil", + "Profile Settings": "Pengaturan Profil", + "Proxy Authentication Required": "Otentikasi proksi diperlukan", + "Railgun Error": "Kesalahan Railgun", + "Range Not Satisfiable": "Rentang Tidak Memuaskan", + "Record": "Catatan", + "Recovery Code": "Kode pemulihan", + "Recovery codes": "Kode pemulihan", + "Recovery codes let you regain access if you lose your 2FA device. Store them in a secure password manager.": "Kode Pemulihan memungkinkan Anda mendapatkan kembali akses jika Anda kehilangan perangkat 2FA Anda. Simpan di manajer kata sandi yang aman.", + "Regards,": "Salam,", + "Regenerate Codes": "Kode Regenerasi", + "Register": "Register", + "Remember me": "Ingat saya", + "Repository": "Gudang", + "Request Header Fields Too Large": "Bidang permintaan Header terlalu besar", + "Request Timeout": "Permintaan waktu habis", + "Resend verification email": "Kirim ulang email verifikasi", + "Reset Content": "Setel ulang konten", + "Reset Password": "Atur Ulang Kata Sandi", + "Reset password": "Setel ulang kata sandi", + "Reset Password Notification": "Pemberitahuan Pengaturan Ulang Kata Sandi", + "Restore": "Pulihkan", + "Restore :name": "Pulihkan :name", + "results": "hasil", + "Retry With": "Coba lagi dengan", + "Save": "Simpan", + "Save & Close": "Simpan & Tutup", + "Save & Return": "Simpan & Kembalikan", + "Save :name": "Hemat :name", + "Saved.": "Disimpan.", + "Search": "Mencari", + "Search :name": "Pencarian :name", + "See Other": "Lihat lainnya", + "Select": "Pilih", + "Select All": "Pilih Semua", + "Send": "Mengirim", + "Server Error": "Terjadi Kesalahan Server", + "Service Unavailable": "Layanan Tidak Tersedia", + "Session Has Expired": "Sesi telah berakhir", + "Settings": "Pengaturan", + "Show": "Menunjukkan", + "Show :name": "Tampilkan :name", + "Show All": "Tunjukkan semua", + "Showing": "Menampilkan", + "Sign In": "Masuk", + "Sign up": "Mendaftar", + "Solve": "Menyelesaikan", + "SSL Handshake Failed": "Jabat tangan SSL gagal", + "Start": "Awal", + "Stop": "Berhenti", + "Submit": "Kirim", + "Subscribe": "Langganan", + "Switch": "Mengalihkan", + "Switch To Role": "Beralih Ke Peran", + "Switching Protocols": "Beralih protokol", + "System": "Sistem", + "Tag": "Menandai", + "Tags": "Tag", + "Temporary Redirect": "Pengalihan temporer", + "The :attribute must be at least :length characters and contain at least one number.": ":Attribute minimal berisi :length karakter dan mengandung setidaknya satu angka.", + "The :attribute must be at least :length characters and contain at least one special character and one number.": ":Attribute minimal berisi :length karakter dan mengandung setidaknya satu karakter spesial dan satu angka.", + "The :attribute must be at least :length characters and contain at least one special character.": ":Attribute minimal berisi :length karakter dan mengandung setidaknya satu karakter spesial.", + "The :attribute must be at least :length characters and contain at least one uppercase character and one number.": ":Attribute minimal berisi :length karakter dan mengandung setidaknya satu huruf besar dan satu angka.", + "The :attribute must be at least :length characters and contain at least one uppercase character and one special character.": ":Attribute minimal berisi :length karakter dan mengandung setidaknya satu huruf besar dan satu karakter spesial.", + "The :attribute must be at least :length characters and contain at least one uppercase character, one number, and one special character.": ":Attribute minimal berisi :length karakter dan mengandung setidaknya satu huruf besar, satu angka, dan satu karakter spesial.", + "The :attribute must be at least :length characters and contain at least one uppercase character.": ":Attribute minimal berisi :length karakter dan mengandung setidaknya satu huruf besar.", + "The :attribute must be at least :length characters.": ":Attribute minimal berisi :length karakter.", + "The given data was invalid.": "Data yang diberikan tidak valid.", + "The provided password does not match your current password.": "Kata sandi yang dimasukkan tidak cocok dengan kata sandi saat ini.", + "The provided password was incorrect.": "Kata sandi yang dimasukkan salah.", + "The provided two factor authentication code was invalid.": "Kode autentikasi dua faktor yang dimasukkan tidak valid.", + "The provided two factor recovery code was invalid.": "Kode pemulihan dua faktor yang diberikan tidak valid.", + "The response is not a streamed response.": "Responsnya bukan respons yang dialirkan.", + "The response is not a view.": "Responsnya bukanlah pandangan.", + "This action is unauthorized.": "Tindakan ini tidak sah.", + "This is a secure area of the application. Please confirm your password before continuing.": "Ini adalah area aplikasi yang aman. Harap konfirmasi kata sandi Anda sebelum melanjutkan.", + "This password reset link will expire in :count minutes.": "Tautan pengaturan ulang kata sandi ini akan kedaluwarsa dalam :count menit.", + "to": "kepada", + "To finish enabling two-factor authentication, scan the QR code or enter the setup key in your authenticator app.": "Untuk menyelesaikan mengaktifkan otentikasi dua faktor, pindai kode QR atau masukkan tombol Pengaturan di aplikasi Authenticator Anda.", + "Toggle navigation": "Alihkan navigasi", + "Too Early": "Terlalu dini", + "Too Many Requests": "Terlalu Banyak Permintaan", + "Translate": "Menerjemahkan", + "Translate It": "Terjemahkan", + "Two Factor Authentication": "Otentikasi dua faktor", + "Two-Factor Auth": "Auth dua faktor", + "Two-Factor Authentication": "Two-Factor Authentication", + "Two-Factor Authentication Enabled": "Otentikasi dua faktor diaktifkan", + "Two-factor authentication is now enabled. Scan the QR code or enter the setup key in your authenticator app.": "Otentikasi dua faktor sekarang diaktifkan. Pindai kode QR atau masukkan tombol Pengaturan di aplikasi Authenticator Anda.", + "Two-Factor Authentication Settings": "Pengaturan Otentikasi Dua Faktor", + "Unauthorized": "Tidak Diizinkan", + "Unavailable For Legal Reasons": "Tidak Tersedia Karena Alasan Hukum", + "Unknown Error": "Error tidak diketahui", + "Unpack": "Membongkar", + "Unprocessable Entity": "Entitas yang tidak dapat diproses", + "Unsubscribe": "Berhenti berlangganan", + "Unsupported Media Type": "Tipe media tidak mendukung", + "Up": "Ke atas", + "Update": "Perbarui", + "Update :name": "Pembaruan :name", + "Update password": "Perbarui Kata Sandi", + "Update the appearance settings for your account": "Perbarui pengaturan tampilan untuk akun Anda", + "Update your name and email address": "Perbarui nama dan alamat email Anda", + "Upgrade Required": "Diperlukan Peningkatan", + "URI Too Long": "URI terlalu panjang", + "Use Proxy": "Memakai Proxy", + "User": "Pengguna", + "Variant Also Negotiates": "Varian Juga Nego", + "Verify Authentication Code": "Verifikasi kode otentikasi", + "Verify Email Address": "Verifikasi Alamat Surel", + "View": "Tampilan", + "View :name": "Lihat :name", + "View Recovery Codes": "Lihat Kode Pemulihan", + "Web Server is Down": "Web server sedang turun", + "Welcome": "Welcome", + "When you enable two-factor authentication, you will be prompted for a secure pin during login. This pin can be retrieved from a TOTP-supported application on your phone.": "Saat Anda mengaktifkan otentikasi dua faktor, Anda akan diminta untuk pin yang aman selama login. Pin ini dapat diambil dari aplikasi yang didukung TOTP di ponsel Anda.", + "Whoops!": "Aduh!", + "With two-factor authentication enabled, you will be prompted for a secure, random pin during login, which you can retrieve from the TOTP-supported application on your phone.": "Dengan otentikasi dua faktor diaktifkan, Anda akan diminta untuk pin acak yang aman selama login, yang dapat Anda ambil dari aplikasi yang didukung TOTP di ponsel Anda.", + "Yes": "Ya", + "You are receiving this email because we received a password reset request for your account.": "Anda menerima surel ini karena kami menerima permintaan pengaturan ulang kata sandi untuk akun anda.", + "Your email address is unverified.": "Alamat surel Anda belum diverifikasi." +} diff --git a/sk-klinik.my.id/lang/id/actions.php b/sk-klinik.my.id/lang/id/actions.php new file mode 100644 index 0000000..0e5cadc --- /dev/null +++ b/sk-klinik.my.id/lang/id/actions.php @@ -0,0 +1,119 @@ + 'Menerima', + 'action' => 'Tindakan', + 'actions' => 'Tindakan', + 'add' => 'Menambahkan', + 'admin' => 'Admin', + 'agree' => 'Setuju', + 'archive' => 'Arsip', + 'assign' => 'Menetapkan', + 'associate' => 'Rekan', + 'attach' => 'Menempel', + 'browse' => 'Jelajahi', + 'cancel' => 'Membatalkan', + 'choose' => 'Memilih', + 'choose_file' => 'Pilih File', + 'choose_image' => 'Pilih Gambar', + 'click_to_copy' => 'Klik untuk menyalin', + 'close' => 'Menutup', + 'collapse' => 'Runtuh', + 'collapse_all' => 'Ciutkan Semua', + 'comment' => 'Komentar', + 'confirm' => 'Mengonfirmasi', + 'connect' => 'Menghubung', + 'create' => 'Membuat', + 'delete' => 'Menghapus', + 'detach' => 'Melepaskan', + 'details' => 'Detail', + 'disable' => 'Cacat', + 'discard' => 'Membuang', + 'done' => 'Selesai', + 'down' => 'Turun', + 'duplicate' => 'Duplikat', + 'edit' => 'Sunting', + 'enable' => 'Memungkinkan', + 'expand' => 'Memperluas', + 'expand_all' => 'Melebarkan semua', + 'explanation' => 'Penjelasan', + 'export' => 'Ekspor', + 'file' => 'Mengajukan', + 'files' => 'File', + 'go_home' => 'Pulang ke rumah', + 'hide' => 'Bersembunyi', + 'home' => 'Rumah', + 'image' => 'Gambar', + 'impersonate' => 'Menirukan', + 'impersonation' => 'Peniruan', + 'import' => 'Impor', + 'introduction' => 'Perkenalan', + 'like' => 'Menyukai', + 'load' => 'Memuat', + 'localize' => 'Melokalisir', + 'log_in' => 'Gabung', + 'log_out' => 'Keluar', + 'named' => [ + 'add' => 'Tambahkan :name', + 'choose' => 'Pilih :name', + 'create' => 'Buat :name', + 'delete' => 'Hapus :name', + 'duplicate' => 'Duplikat: nama', + 'edit' => 'Sunting :name', + 'export' => 'Export :name', + 'hide' => 'Sembunyikan :name', + 'import' => 'Impor :name', + 'new' => 'Baru :name', + 'restore' => 'Pulihkan :name', + 'save' => 'Hemat :name', + 'search' => 'Pencarian :name', + 'show' => 'Tampilkan :name', + 'update' => 'Pembaruan :name', + 'view' => 'Lihat :name', + ], + 'new' => 'Baru', + 'no' => 'TIDAK', + 'open' => 'Membuka', + 'open_website' => 'Buka di situs web', + 'preview' => 'Pratinjau', + 'price' => 'Harga', + 'record' => 'Catatan', + 'restore' => 'Memulihkan', + 'save' => 'Menyimpan', + 'save_and_close' => 'Simpan & Tutup', + 'save_and_return' => 'Simpan & Kembalikan', + 'search' => 'Mencari', + 'select' => 'Pilih', + 'select_all' => 'Pilih Semua', + 'send' => 'Mengirim', + 'settings' => 'Pengaturan', + 'show' => 'Menunjukkan', + 'show_all' => 'Tunjukkan semua', + 'sign_in' => 'Masuk', + 'solve' => 'Menyelesaikan', + 'start' => 'Awal', + 'stop' => 'Berhenti', + 'submit' => 'Kirim', + 'subscribe' => 'Langganan', + 'switch' => 'Mengalihkan', + 'switch_to_role' => 'Beralih Ke Peran', + 'tag' => 'Menandai', + 'tags' => 'Tag', + 'target_link' => [ + 'blank' => 'Buka di jendela baru', + 'parent' => 'Buka di bingkai induk', + 'self' => 'Buka di jendela saat ini', + 'top' => 'Buka di bingkai paling atas', + ], + 'translate' => 'Menerjemahkan', + 'translate_it' => 'Terjemahkan', + 'unpack' => 'Membongkar', + 'unsubscribe' => 'Berhenti berlangganan', + 'up' => 'Ke atas', + 'update' => 'Memperbarui', + 'user' => 'Pengguna', + 'view' => 'Melihat', + 'yes' => 'Ya', +]; diff --git a/sk-klinik.my.id/lang/id/auth.php b/sk-klinik.my.id/lang/id/auth.php new file mode 100644 index 0000000..030b6b7 --- /dev/null +++ b/sk-klinik.my.id/lang/id/auth.php @@ -0,0 +1,9 @@ + 'Identitas tersebut tidak cocok dengan data kami.', + 'password' => 'Kata sandi salah.', + 'throttle' => 'Terlalu banyak upaya masuk. Silahkan coba lagi dalam :seconds detik.', +]; diff --git a/sk-klinik.my.id/lang/id/http-statuses.php b/sk-klinik.my.id/lang/id/http-statuses.php new file mode 100644 index 0000000..f485265 --- /dev/null +++ b/sk-klinik.my.id/lang/id/http-statuses.php @@ -0,0 +1,84 @@ + 'Error tidak diketahui', + '100' => 'Lanjut', + '101' => 'Beralih protokol', + '102' => 'Memproses', + '200' => 'OKE', + '201' => 'Dibuat', + '202' => 'Diterima', + '203' => 'Informasi Non-Otoritatif', + '204' => 'Tidak ada konten', + '205' => 'Setel ulang konten', + '206' => 'Konten parsial', + '207' => 'Status ganda', + '208' => 'Sudah dilaporkan', + '226' => 'IM Digunakan', + '300' => 'Pilihan ganda', + '301' => 'Pengalihan permanen', + '302' => 'Ditemukan', + '303' => 'Lihat lainnya', + '304' => 'Tidak dimodifikasi', + '305' => 'Memakai Proxy', + '307' => 'Pengalihan temporer', + '308' => 'Pengalihan permanen', + '400' => 'Permintaan yang buruk', + '401' => 'Tidak sah', + '402' => 'Pembayaran diperlukan', + '403' => 'Terlarang', + '404' => 'Tidak ditemukan', + '405' => 'Metode tidak diizinkan', + '406' => 'Tidak dapat diterima', + '407' => 'Otentikasi proksi diperlukan', + '408' => 'Permintaan waktu habis', + '409' => 'Konflik', + '410' => 'Hilang', + '411' => 'Panjang diperlukan', + '412' => 'Prasyarat Gagal', + '413' => 'Payload terlalu besar', + '414' => 'URI terlalu panjang', + '415' => 'Tipe media tidak mendukung', + '416' => 'Rentang Tidak Memuaskan', + '417' => 'Ekspetasi gagal', + '418' => 'Saya teko', + '419' => 'Sesi telah berakhir', + '421' => 'Permintaan salah arah', + '422' => 'Entitas yang tidak dapat diproses', + '423' => 'Terkunci', + '424' => 'Dependensi gagal', + '425' => 'Terlalu dini', + '426' => 'Diperlukan Peningkatan', + '428' => 'Prasyarat diperlukan', + '429' => 'Terlalu banyak permintaan', + '431' => 'Bidang permintaan Header terlalu besar', + '444' => 'Koneksi Ditutup Tanpa Respon', + '449' => 'Coba lagi dengan', + '451' => 'Tidak Tersedia Karena Alasan Hukum', + '499' => 'Permintaan ditutup klien', + '500' => 'Kesalahan dari dalam server', + '501' => 'Tidak dilaksanakan', + '502' => 'Gateway buruk', + '503' => 'Mode pemeliharaan', + '504' => 'Gateway waktu habis', + '505' => 'Versi HTTP tidak mendukung', + '506' => 'Varian Juga Nego', + '507' => 'Penyimpanan tidak cukup', + '508' => 'Terdeteksi perulangan', + '509' => 'Batas Bandwidth terlampaui', + '510' => 'Tidak diperpanjang', + '511' => 'Otentikasi jaringan diperlukan', + '520' => 'Error tidak diketahui', + '521' => 'Web server sedang turun', + '522' => 'Waktu koneksi berakhir', + '523' => 'Asal tidak terjangkau', + '524' => 'Terjadi Timeout', + '525' => 'Jabat tangan SSL gagal', + '526' => 'Sertifikat SSL tidak sah', + '527' => 'Kesalahan Railgun', + '598' => 'Network Read Timeout gagal', + '599' => 'Network Connect Timeout gagal', + 'unknownError' => 'Error tidak diketahui', +]; diff --git a/sk-klinik.my.id/lang/id/pagination.php b/sk-klinik.my.id/lang/id/pagination.php new file mode 100644 index 0000000..708a9f0 --- /dev/null +++ b/sk-klinik.my.id/lang/id/pagination.php @@ -0,0 +1,8 @@ + 'Berikutnya »', + 'previous' => '« Sebelumnya', +]; diff --git a/sk-klinik.my.id/lang/id/passwords.php b/sk-klinik.my.id/lang/id/passwords.php new file mode 100644 index 0000000..7308604 --- /dev/null +++ b/sk-klinik.my.id/lang/id/passwords.php @@ -0,0 +1,11 @@ + 'Kata sandi Anda sudah direset!', + 'sent' => 'Kami sudah mengirim surel yang berisi tautan untuk mereset kata sandi Anda!', + 'throttled' => 'Harap tunggu sebelum mencoba lagi.', + 'token' => 'Token pengaturan ulang kata sandi tidak sah.', + 'user' => 'Kami tidak dapat menemukan pengguna dengan alamat surel tersebut.', +]; diff --git a/sk-klinik.my.id/lang/id/validation.php b/sk-klinik.my.id/lang/id/validation.php new file mode 100644 index 0000000..9fe0fa2 --- /dev/null +++ b/sk-klinik.my.id/lang/id/validation.php @@ -0,0 +1,288 @@ + ':Attribute harus diterima.', + 'accepted_if' => ':Attribute harus diterima ketika :other berisi :value.', + 'active_url' => ':Attribute bukan URL yang valid.', + 'after' => ':Attribute harus berisi tanggal setelah :date.', + 'after_or_equal' => ':Attribute harus berisi tanggal setelah atau sama dengan :date.', + 'alpha' => ':Attribute hanya boleh berisi huruf.', + 'alpha_dash' => ':Attribute hanya boleh berisi huruf, angka, strip, dan garis bawah.', + 'alpha_num' => ':Attribute hanya boleh berisi huruf dan angka.', + 'any_of' => 'Bidang :attribute tidak valid.', + 'array' => ':Attribute harus berisi sebuah array.', + 'ascii' => ':Attribute hanya boleh berisi karakter dan simbol alfanumerik single-byte.', + 'before' => ':Attribute harus berisi tanggal sebelum :date.', + 'before_or_equal' => ':Attribute harus berisi tanggal sebelum atau sama dengan :date.', + 'between' => [ + 'array' => ':Attribute harus memiliki :min sampai :max anggota.', + 'file' => ':Attribute harus berukuran antara :min sampai :max kilobita.', + 'numeric' => ':Attribute harus bernilai antara :min sampai :max.', + 'string' => ':Attribute harus berisi antara :min sampai :max karakter.', + ], + 'boolean' => ':Attribute harus bernilai true atau false', + 'can' => 'Bidang :attribute berisi nilai yang tidak sah.', + 'confirmed' => 'Konfirmasi :attribute tidak cocok.', + 'contains' => 'Bidang :attribute tidak memiliki nilai yang diperlukan.', + 'current_password' => 'Kata sandi salah.', + 'date' => ':Attribute bukan tanggal yang valid.', + 'date_equals' => ':Attribute harus berisi tanggal yang sama dengan :date.', + 'date_format' => ':Attribute tidak cocok dengan format :format.', + 'decimal' => ':Attribute harus memiliki :decimal tempat desimal.', + 'declined' => ':Attribute ini harus ditolak.', + 'declined_if' => ':Attribute ini harus ditolak ketika :other bernilai :value.', + 'different' => ':Attribute dan :other harus berbeda.', + 'digits' => ':Attribute harus terdiri dari :digits angka.', + 'digits_between' => ':Attribute harus terdiri dari :min sampai :max angka.', + 'dimensions' => ':Attribute tidak memiliki dimensi gambar yang valid.', + 'distinct' => ':Attribute memiliki nilai yang duplikat.', + 'doesnt_contain' => 'Bidang :attribute tidak boleh berisi salah satu dari yang berikut: :values.', + 'doesnt_end_with' => ':Attribute tidak boleh diakhiri dengan salah satu dari berikut ini: :values.', + 'doesnt_start_with' => ':Attribute tidak boleh dimulai dengan salah satu dari berikut ini: :values.', + 'email' => ':Attribute harus berupa alamat surel yang valid.', + 'encoding' => 'Bidang :attribute harus dikodekan dalam :encoding.', + 'ends_with' => ':Attribute harus diakhiri salah satu dari berikut: :values', + 'enum' => ':Attribute yang dipilih tidak valid.', + 'exists' => ':Attribute yang dipilih tidak valid.', + 'extensions' => 'Bidang :attribute harus memiliki salah satu ekstensi berikut: :values.', + 'file' => ':Attribute harus berupa sebuah berkas.', + 'filled' => ':Attribute harus memiliki nilai.', + 'gt' => [ + 'array' => ':Attribute harus memiliki lebih dari :value anggota.', + 'file' => ':Attribute harus berukuran lebih besar dari :value kilobita.', + 'numeric' => ':Attribute harus bernilai lebih besar dari :value.', + 'string' => ':Attribute harus berisi lebih besar dari :value karakter.', + ], + 'gte' => [ + 'array' => ':Attribute harus terdiri dari :value anggota atau lebih.', + 'file' => ':Attribute harus berukuran lebih besar dari atau sama dengan :value kilobita.', + 'numeric' => ':Attribute harus bernilai lebih besar dari atau sama dengan :value.', + 'string' => ':Attribute harus berisi lebih besar dari atau sama dengan :value karakter.', + ], + 'hex_color' => 'Bidang :attribute harus berupa warna heksadesimal yang valid.', + 'image' => ':Attribute harus berupa gambar.', + 'in' => ':Attribute yang dipilih tidak valid.', + 'in_array' => ':Attribute tidak ada di dalam :other.', + 'in_array_keys' => ':attribute bidang harus berisi setidaknya satu dari tombol berikut: :values.', + 'integer' => ':Attribute harus berupa bilangan bulat.', + 'ip' => ':Attribute harus berupa alamat IP yang valid.', + 'ipv4' => ':Attribute harus berupa alamat IPv4 yang valid.', + 'ipv6' => ':Attribute harus berupa alamat IPv6 yang valid.', + 'json' => ':Attribute harus berupa JSON string yang valid.', + 'list' => 'Bidang :attribute harus berupa daftar.', + 'lowercase' => ':Attribute harus berupa huruf kecil.', + 'lt' => [ + 'array' => ':Attribute harus memiliki kurang dari :value anggota.', + 'file' => ':Attribute harus berukuran kurang dari :value kilobita.', + 'numeric' => ':Attribute harus bernilai kurang dari :value.', + 'string' => ':Attribute harus berisi kurang dari :value karakter.', + ], + 'lte' => [ + 'array' => ':Attribute harus tidak lebih dari :value anggota.', + 'file' => ':Attribute harus berukuran kurang dari atau sama dengan :value kilobita.', + 'numeric' => ':Attribute harus bernilai kurang dari atau sama dengan :value.', + 'string' => ':Attribute harus berisi kurang dari atau sama dengan :value karakter.', + ], + 'mac_address' => ':Attribute harus berupa alamat MAC yang valid.', + 'max' => [ + 'array' => ':Attribute maksimal terdiri dari :max anggota.', + 'file' => ':Attribute maksimal berukuran :max kilobita.', + 'numeric' => ':Attribute maksimal bernilai :max.', + 'string' => ':Attribute maksimal berisi :max karakter.', + ], + 'max_digits' => ':Attribute tidak boleh memiliki lebih dari :max digit.', + 'mimes' => ':Attribute harus berupa berkas berjenis: :values.', + 'mimetypes' => ':Attribute harus berupa berkas berjenis: :values.', + 'min' => [ + 'array' => ':Attribute minimal terdiri dari :min anggota.', + 'file' => ':Attribute minimal berukuran :min kilobita.', + 'numeric' => ':Attribute minimal bernilai :min.', + 'string' => ':Attribute minimal berisi :min karakter.', + ], + 'min_digits' => ':Attribute tidak boleh memiliki kurang dari :min digit.', + 'missing' => 'Bidang :attribute harus hilang.', + 'missing_if' => 'Bidang :attribute harus hilang ketika :other adalah :value.', + 'missing_unless' => 'Bidang :attribute harus hilang kecuali :other adalah :value.', + 'missing_with' => 'Kolom :attribute harus hilang saat ada :values.', + 'missing_with_all' => 'Kolom :attribute harus hilang jika ada :values.', + 'multiple_of' => ':Attribute harus merupakan kelipatan dari :value', + 'not_in' => ':Attribute yang dipilih tidak valid.', + 'not_regex' => 'Format :attribute tidak valid.', + 'numeric' => ':Attribute harus berupa angka.', + 'password' => [ + 'letters' => ':Attribute ini harus memiliki setidaknya satu karakter.', + 'mixed' => ':Attribute ini harus memiliki setidaknya satu huruf kapital dan satu huruf kecil.', + 'numbers' => ':Attribute ini harus memiliki setidaknya satu angka.', + 'symbols' => ':Attribute ini harus memiliki setidaknya satu simbol.', + 'uncompromised' => ':Attribute ini telah muncul di kebocoran data. Silahkan memilih :attribute yang berbeda.', + ], + 'present' => ':Attribute wajib ada.', + 'present_if' => 'Bidang :attribute harus ada ketika :other adalah :value.', + 'present_unless' => 'Bidang :attribute harus ada kecuali :other adalah :value.', + 'present_with' => 'Bidang :attribute harus ada bila ada :values.', + 'present_with_all' => 'Bidang :attribute harus ada ketika ada :values.', + 'prohibited' => ':Attribute tidak boleh ada.', + 'prohibited_if' => ':Attribute tidak boleh ada bila :other adalah :value.', + 'prohibited_if_accepted' => ':attribute bidang dilarang ketika :other diterima.', + 'prohibited_if_declined' => ':attribute bidang dilarang ketika :other ditolak.', + 'prohibited_unless' => ':Attribute tidak boleh ada kecuali :other memiliki nilai :values.', + 'prohibits' => ':Attribute melarang isian :other untuk ditampilkan.', + 'regex' => 'Format :attribute tidak valid.', + 'required' => ':Attribute wajib diisi.', + 'required_array_keys' => ':Attribute wajib berisi entri untuk: :values.', + 'required_if' => ':Attribute wajib diisi bila :other adalah :value.', + 'required_if_accepted' => ':Attribute wajib diisi bila :other sesuai.', + 'required_if_declined' => 'Bidang :attribute wajib diisi bila :other ditolak.', + 'required_unless' => ':Attribute wajib diisi kecuali :other memiliki nilai :values.', + 'required_with' => ':Attribute wajib diisi bila terdapat :values.', + 'required_with_all' => ':Attribute wajib diisi bila terdapat :values.', + 'required_without' => ':Attribute wajib diisi bila tidak terdapat :values.', + 'required_without_all' => ':Attribute wajib diisi bila sama sekali tidak terdapat :values.', + 'same' => ':Attribute dan :other harus sama.', + 'size' => [ + 'array' => ':Attribute harus mengandung :size anggota.', + 'file' => ':Attribute harus berukuran :size kilobyte.', + 'numeric' => ':Attribute harus berukuran :size.', + 'string' => ':Attribute harus berukuran :size karakter.', + ], + 'starts_with' => ':Attribute harus diawali salah satu dari berikut: :values', + 'string' => ':Attribute harus berupa string.', + 'timezone' => ':Attribute harus berisi zona waktu yang valid.', + 'ulid' => ':Attribute harus merupakan ULID yang valid.', + 'unique' => ':Attribute sudah ada sebelumnya.', + 'uploaded' => ':Attribute gagal diunggah.', + 'uppercase' => ':Attribute harus berupa huruf kapital.', + 'url' => 'Format :attribute tidak valid.', + 'uuid' => ':Attribute harus merupakan UUID yang valid.', + 'attributes' => [ + 'address' => 'alamat', + 'affiliate_url' => 'URL afiliasi', + 'age' => 'usia', + 'amount' => 'jumlah', + 'announcement' => 'pengumuman', + 'area' => 'daerah', + 'audience_prize' => 'hadiah penonton', + 'audience_winner' => 'audience winner', + 'available' => 'tersedia', + 'birthday' => 'hari ulang tahun', + 'body' => 'badan', + 'city' => 'kota', + 'color' => 'color', + 'company' => 'company', + 'compilation' => 'kompilasi', + 'concept' => 'konsep', + 'conditions' => 'kondisi', + 'content' => 'konten', + 'contest' => 'contest', + 'country' => 'negara', + 'cover' => 'menutupi', + 'created_at' => 'dibuat di', + 'creator' => 'pencipta', + 'currency' => 'mata uang', + 'current_password' => 'kata sandi saat ini', + 'customer' => 'pelanggan', + 'date' => 'tanggal', + 'date_of_birth' => 'tanggal lahir', + 'dates' => 'tanggal', + 'day' => 'hari', + 'deleted_at' => 'dihapus pada', + 'description' => 'deskripsi', + 'display_type' => 'tipe tampilan', + 'district' => 'daerah', + 'duration' => 'durasi', + 'email' => 'surel', + 'excerpt' => 'kutipan', + 'filter' => 'Saring', + 'finished_at' => 'selesai pada', + 'first_name' => 'nama depan', + 'gender' => 'jenis kelamin', + 'grand_prize' => 'hadiah utama', + 'group' => 'kelompok', + 'hour' => 'jam', + 'image' => 'gambar', + 'image_desktop' => 'gambar desktop', + 'image_main' => 'gambar utama', + 'image_mobile' => 'gambar seluler', + 'images' => 'gambar-gambar', + 'is_audience_winner' => 'adalah pemenang penonton', + 'is_hidden' => 'tersembunyi', + 'is_subscribed' => 'berlangganan', + 'is_visible' => 'terlihat', + 'is_winner' => 'adalah pemenang', + 'items' => 'item', + 'key' => 'kunci', + 'last_name' => 'nama belakang', + 'lesson' => 'pelajaran', + 'line_address_1' => 'alamat baris 1', + 'line_address_2' => 'alamat baris 2', + 'login' => 'Gabung', + 'message' => 'pesan', + 'middle_name' => 'nama tengah', + 'minute' => 'menit', + 'mobile' => 'seluler', + 'month' => 'bulan', + 'name' => 'nama', + 'national_code' => 'kode nasional', + 'number' => 'nomor', + 'password' => 'kata sandi', + 'password_confirmation' => 'konfirmasi kata sandi', + 'phone' => 'telepon', + 'photo' => 'foto', + 'portfolio' => 'portofolio', + 'postal_code' => 'kode Pos', + 'preview' => 'pratinjau', + 'price' => 'harga', + 'product_id' => 'ID Produk', + 'product_uid' => 'UID produk', + 'product_uuid' => 'UUID produk', + 'promo_code' => 'Kode promosi', + 'province' => 'propinsi', + 'quantity' => 'kuantitas', + 'reason' => 'alasan', + 'recaptcha_response_field' => 'bidang respons recaptcha', + 'referee' => 'wasit', + 'referees' => 'wasit', + 'region' => 'region', + 'reject_reason' => 'menolak alasan', + 'remember' => 'ingat', + 'restored_at' => 'dipulihkan pada', + 'result_text_under_image' => 'teks hasil di bawah gambar', + 'role' => 'peran', + 'rule' => 'aturan', + 'rules' => 'aturan', + 'second' => 'detik', + 'sex' => 'jenis kelamin', + 'shipment' => 'pengiriman', + 'short_text' => 'teks pendek', + 'size' => 'ukuran', + 'skills' => 'keterampilan', + 'slug' => 'siput', + 'specialization' => 'spesialisasi', + 'started_at' => 'dimulai pada', + 'state' => 'negara', + 'status' => 'status', + 'street' => 'jalan', + 'student' => 'siswa', + 'subject' => 'subyek', + 'tag' => 'menandai', + 'tags' => 'tag', + 'teacher' => 'guru', + 'terms' => 'ketentuan', + 'test_description' => 'deskripsi tes', + 'test_locale' => 'uji lokal', + 'test_name' => 'nama tes', + 'text' => 'teks', + 'time' => 'waktu', + 'title' => 'judul', + 'type' => 'jenis', + 'updated_at' => 'diperbarui pada', + 'user' => 'pengguna', + 'username' => 'nama pengguna', + 'value' => 'nilai', + 'winner' => 'winner', + 'work' => 'work', + 'year' => 'tahun', + ], +]; diff --git a/sk-klinik.my.id/package-lock.json b/sk-klinik.my.id/package-lock.json new file mode 100644 index 0000000..3275b6b --- /dev/null +++ b/sk-klinik.my.id/package-lock.json @@ -0,0 +1,2617 @@ +{ + "name": "sk-klinik.my.id", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@tailwindcss/vite": "^4.1.11", + "autoprefixer": "^10.4.20", + "axios": "^1.7.4", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^2.0", + "sweetalert2": "^11.26.22", + "tailwindcss": "^4.0.7", + "trix": "^2.1.17", + "vite": "^7.0.4" + }, + "devDependencies": { + "html5-qrcode": "^2.3.8" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "4.9.5", + "@tailwindcss/oxide-linux-x64-gnu": "^4.0.1", + "lightningcss-linux-x64-gnu": "^1.29.1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.9.5", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.5.tgz", + "integrity": "sha512-Dq1bqBdLaZ1Gb/l2e5/+o3B18+8TI9ANlA1SkejZqDgdU/jK/ThYaMPMJpVMMXy2uRHvGKbkz9vheVGdq3cJfA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/node/-/node-4.3.0.tgz", + "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.21.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide/-/oxide-4.3.0.tgz", + "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-x64": "4.3.0", + "@tailwindcss/oxide-freebsd-x64": "4.3.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-x64-musl": "4.3.0", + "@tailwindcss/oxide-wasm32-wasi": "4.3.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", + "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", + "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", + "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", + "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/@tailwindcss/vite/-/vite-4.3.0.tgz", + "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "tailwindcss": "4.3.0" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.16.1", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.31", + "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.31.tgz", + "integrity": "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmmirror.com/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dompurify": { + "version": "3.4.5", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.5.tgz", + "integrity": "sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.360", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.360.tgz", + "integrity": "sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.21.5", + "resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.21.5.tgz", + "integrity": "sha512-mLCNbrQli11K1ySUmuNt4ZUB3OpGIDq4q2vTBTf5cL2lpsRjI9QKqSD0ndjW8FyvcW/Jj46gMe9syyHAsvMa/A==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html5-qrcode": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/html5-qrcode/-/html5-qrcode-2.3.8.tgz", + "integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/laravel-vite-plugin": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/laravel-vite-plugin/-/laravel-vite-plugin-2.1.0.tgz", + "integrity": "sha512-z+ck2BSV6KWtYcoIzk9Y5+p4NEjqM+Y4i8/H+VZRLq0OgNjW2DqyADquwYu5j8qRvaXwzNmfCWl1KrMlV1zpsg==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "vite-plugin-full-reload": "^1.1.0" + }, + "bin": { + "clean-orphaned-assets": "bin/clean.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^7.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.44", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.44.tgz", + "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/sweetalert2": { + "version": "11.26.24", + "resolved": "https://registry.npmmirror.com/sweetalert2/-/sweetalert2-11.26.24.tgz", + "integrity": "sha512-SLgukW4wicewpW5VOukSXY5Z6DL/z7HCOK2ODSjmQPiSphCN8gJAmh9npoceXOtBRNoDN0xIz+zHYthtfiHmjg==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/limonte" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.3.0.tgz", + "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trix": { + "version": "2.1.19", + "resolved": "https://registry.npmmirror.com/trix/-/trix-2.1.19.tgz", + "integrity": "sha512-E7RA3EOeUiUwNJlrF5onIOkqCA06xUU6GmHOVxXyMnGMValrDK3Ce7uaMVgiVUOvVt4mzUERAHAzD10mxoLpOg==", + "license": "MIT", + "dependencies": { + "dompurify": "^3.2.5" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "7.3.3", + "resolved": "https://registry.npmmirror.com/vite/-/vite-7.3.3.tgz", + "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-full-reload": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", + "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "picomatch": "^2.3.1" + } + }, + "node_modules/vite-plugin-full-reload/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/sk-klinik.my.id/package.json b/sk-klinik.my.id/package.json new file mode 100644 index 0000000..25f3050 --- /dev/null +++ b/sk-klinik.my.id/package.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://www.schemastore.org/package.json", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.11", + "autoprefixer": "^10.4.20", + "axios": "^1.7.4", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^2.0", + "sweetalert2": "^11.26.22", + "tailwindcss": "^4.0.7", + "trix": "^2.1.17", + "vite": "^7.0.4" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "4.9.5", + "@tailwindcss/oxide-linux-x64-gnu": "^4.0.1", + "lightningcss-linux-x64-gnu": "^1.29.1" + }, + "devDependencies": { + "html5-qrcode": "^2.3.8" + } +} diff --git a/sk-klinik.my.id/phpunit.xml b/sk-klinik.my.id/phpunit.xml new file mode 100644 index 0000000..e7f0a48 --- /dev/null +++ b/sk-klinik.my.id/phpunit.xml @@ -0,0 +1,36 @@ + + + + + tests/Unit + + + tests/Feature + + + + + app + + + + + + + + + + + + + + + + + + + diff --git a/sk-klinik.my.id/pint.json b/sk-klinik.my.id/pint.json new file mode 100644 index 0000000..93061b6 --- /dev/null +++ b/sk-klinik.my.id/pint.json @@ -0,0 +1,3 @@ +{ + "preset": "laravel" +} diff --git a/sk-klinik.my.id/public/.htaccess b/sk-klinik.my.id/public/.htaccess new file mode 100644 index 0000000..b574a59 --- /dev/null +++ b/sk-klinik.my.id/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/sk-klinik.my.id/public/apple-touch-icon.png b/sk-klinik.my.id/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c2efef6de4482ad4ec770787891fb3ab7f7b1f58 GIT binary patch literal 1662 zcmV-^27&pBP)40{{R3XI2D70000&P)t-s00030 zFd+XeApb8Q|1BW@E+GFcApbBR|1Kc^Eg=6bApb5P|1Kc^EFk|aApa~N|1BW@Eg=6e zApb5P|1BW@Eg&n7Ql0<+02OpnPE!CNzd)dXU=ZKm?|<)rkZ`ZhFmF)fpgb%900q`b zL_t(|+U%Oqj+-zLMaMYBBrGf>;s1ZNY7`jIiI_O8!Rm4!Tgf`>xtSR*$bTdkB!69t zVK_O-TcI8P=u%70x?P5+&ZXoke;#Hk@~pfohJ~`UXs9Q;_B2)gTk?{cvbc)et1K<* zr+Qaj9xAKsDzB#eYQpr7r@Sm0>dVCQfKCB0Kf{y|EP9n~<+TZwVye09V$sm9n9{PSY^C}VzXiE}GC#|%c)PWA z!&5y>`JP4VkDV6b8$Z_jJJu@A$QeFse^IT?qj=G4l>4y#(Kj|Guiq{iFk{=Fwl*76 z)xQ4|>IRkjy#1lI8JM_!yJWG>8ZJNf8dXXx zrk~GbPG4tWE+u0Q(BCgl#w@cPJ5nx)T9MuG26Ggy6OkTfT zvPjI^>P)^G7FA5^`aMfVOxu)|x2A9549ulPjgm!RI{t-}!yN(BSbnfZ0rTAmB^Yxa z0ShsC{k=0v223kLF@%7Hn5rZ4wL=GnpitveraoqSfe(_EIcO5du!CjnDf@wtxv3e z-u^bn6xYI{>k~_4b4*0{)`LMCWEV`GECi(~y~rMz#`428YDY}1JOdWj&DW^?F-Ib; zJl{lRfw{1#A0resWj2_y2v`;oie!a3x9HrIxnXL+G9OMEVvZJ7Q)Y@O(#)P#Gsb*Y zz6+8!=6Lpjd0-xx2j+o!U>=wU<`2TWpY@?U`fOKhgXs$-hQ`^*57T3Y7GFKsXEUm) zBmpLJD?F4LXCptnrod!)-s4>q&NlMH1ep8=0k2DW_S$RM1ei2s8;}?pXCpsMfQj(j zNDOf{^1}p}D=)N>81ii9hY2uO&CkS;XEQ%chDr0UB!)N}`C$S~^BV*vhRd^&A11-1 z`R$K=!+176!AgetySX#KX&8o~XtND<+Gs@?_dhEVl?dUf^KAF4`3KmZ#1o5M$8F`` z3P!Tl&&CLr3Ul6+|GA>4A2dj*!Zf~z9YX~DLkTA3XY8i74zs-cJ)DTceLfYYA-}08 zCfNm;#x)M#D5naO^M{f7;@Z>}U}BCre7ypnoy1IDM_|xHKkNy25-bsNjhURKb+p6ga^RJ>eNU6hI2E^Ow5A+W|JeZDC8Wqj7Y8Fr9@Uvc=cY`i& zDS4WCQI*lV*os&Gro@tzcjHTqy#y%$-R|Mc0;Z=P9R-{!<>DZ*bg~pkU*-o&W#<07*qo IM6N<$f;hnhc>n+a literal 0 HcmV?d00001 diff --git a/sk-klinik.my.id/public/favicon.ico b/sk-klinik.my.id/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..236fadb94188e9189807c50aa8480b3070a0cc8d GIT binary patch literal 4286 zcmcJSYiv|S6vqb^Sj9>!kD_?#USEjFuB*k05m`ulKhQ)0{ZR3Nj~ES!#h9qrHiD>$ zFCbA83#r6d--z!Q-dZre@B@j4kBxrw(=r7ZdN&YYP!=ggUN z&s>a|z(3zN`fK`{jA=H;%m+kf8A$GajE&{z=dAJbc7mU^S=a@A(CVLujIm?&L%;DC zLe@6JdI;b*I0WCqqi~9wGmd_s)3`n7>{QyT;Y-k-FM>{Z23kR}*bD8AB1Y}dT<%4|D*yFG{ipz1dZ-md_9asjFVAL*Xjeow=eI@kwWU_SmSU;ft*cgCUqSjPbCwmKa-bR^DI`k=CZ?Ca;^-d5Ll<&7I3$q~lW zumU~>#c()c$ zznq=I*j4Zy`~=s7e6N}x_jxK`Zh-@E10+?J+sM~|@>qVCnUcYu{D&HP^q=+0M}32-cM_!3Ciyi+W;gJQ1O$7`Uq{%qEf zQ&BAEGXHHD1l564qg*VjMHc7h8MJr9F#HPgp`07>0%S*IU-OwO9s`}T@>+3T1B!b* zKArZ1un%4W-3_mTYTL(f9k{v?=^U+ny>m|ylSw>PH%q64pG5ofa4((kv;&-?dWdAkLy`uhG@CDoiOQ8?+ z9kmLbnp3s^M6T<5NBhy**WqFab58X;{Fc}ICS9`EhD_t_k?aMYs+oF+X2x}$w)C!s zub>y+giUTd`u=o2$VPbg%w}A5K=FGP&VnVNeaN?!pjv4BMJ}c{)BXz-le3+UDBqmk zP^aQH6SlzLumSXcGEJ%aDelxC<@f^F20w!KrQDna?i}Mq^k;zX6#3f)bNvO(k)BF^ zHzB_V0(cothr0F?dSz!aw81>*Q(|8=^W<+HdO$YTVt*Rwysv=|;RCn=q%&SVZcpiq z>|ITJ5A23ruovR@SbG{bo3)A(@mAf`d#C(4&3${+iCyjbvGi?Vt?lZx!zN>grl)PO zquU0hL7OTS3ys0yLdGmDv^2C7yp|~iFVkJ{(t`!Bd#K + + diff --git a/sk-klinik.my.id/public/images/hero-klinik.jpg b/sk-klinik.my.id/public/images/hero-klinik.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b32cd7759804e96de78775401b3aedb55ac604df GIT binary patch literal 190595 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 Ax&QzG literal 0 HcmV?d00001 diff --git a/sk-klinik.my.id/public/images/logo.png b/sk-klinik.my.id/public/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..786da943becc2045d0f295f165a312999e5e176f GIT binary patch literal 44864 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 IM6N<$f;sLkH2?qr literal 0 HcmV?d00001 diff --git a/sk-klinik.my.id/public/index.php b/sk-klinik.my.id/public/index.php new file mode 100644 index 0000000..ee8f07e --- /dev/null +++ b/sk-klinik.my.id/public/index.php @@ -0,0 +1,20 @@ +handleRequest(Request::capture()); diff --git a/sk-klinik.my.id/public/phpliteadmin/index.php b/sk-klinik.my.id/public/phpliteadmin/index.php new file mode 100644 index 0000000..0d241d9 --- /dev/null +++ b/sk-klinik.my.id/public/phpliteadmin/index.php @@ -0,0 +1,6177 @@ +. +// +// //////////////////////////////////////////////////////////////////////// +// +// Please report any bugs you may encounter to our issue tracker here: +// https://bitbucket.org/phpliteadmin/public/issues?status=new&status=open + +// +// This is sample configuration file +// +// You can configure phpliteadmin in one of 2 ways: +// 1. Rename phpliteadmin.config.sample.php to phpliteadmin.config.php and change parameters in there. +// You can set only your custom settings in phpliteadmin.config.php. All other settings will be set to defaults. +// 2. Change parameters directly in main phpliteadmin.php file +// +// Please see https://bitbucket.org/phpliteadmin/public/wiki/Configuration for more details + +//password to gain access +$password = ''; + +//directory relative to this file to search for databases (if false, manually list databases in the $databases variable) +$directory = '/www/wwwroot/sk-klinik.my.id/database'; + +//whether or not to scan the subdirectories of the above directory infinitely deep +$subdirectories = true; + +//if the above $directory variable is set to false, you must specify the databases manually in an array as the next variable +//if any of the databases do not exist as they are referenced by their path, they will be created automatically +$databases = array( + array( + 'path'=> '/www/wwwroot/sk-klinik.my.id/database/database.sqlite', + 'name'=> 'Database 1' + ), +); + + +/* ---- Interface settings ---- */ + +// Theme! If you want to change theme, save the CSS file in same folder of phpliteadmin or in folder "themes" +$theme = 'phpliteadmin.css'; + +// the default language! If you want to change it, save the language file in same folder of phpliteadmin or in folder "languages" +// More about localizations (downloads, how to translate etc.): https://bitbucket.org/phpliteadmin/public/wiki/Localization +$language = 'en'; + +// set default number of rows. You need to relog after changing the number +$rowsNum = 30; + +// reduce string characters by a number bigger than 10 +$charsNum = 300; + +// maximum number of SQL queries to save in the history +$maxSavedQueries = 10; + +/* ---- Custom functions ---- */ + +//a list of custom functions that can be applied to columns in the databases +//make sure to define every function below if it is not a core PHP function +$custom_functions = array( + 'md5', 'sha1', 'time', 'strtotime', + // add the names of your custom functions to this array + /* 'leet_text', */ +); + +// define your custom functions here +/* +function leet_text($value) +{ + return strtr($value, 'eaAsSOl', '344zZ01'); +} +*/ + + +/* ---- Advanced options ---- */ + +//changing the following variable allows multiple phpLiteAdmin installs to work under the same domain. +$cookie_name = 'pla3412'; + +//whether or not to put the app in debug mode where errors are outputted +$debug = false; + +// the user is allowed to create databases with only these extensions +$allowed_extensions = array('db','db3','sqlite','sqlite3'); + + +// English language-texts. +// Read our wiki on how to translate: https://bitbucket.org/phpliteadmin/public/wiki/Localization +$lang = array( + "direction" => "LTR", + "date_format" => 'g:ia \o\n F j, Y (T)', // see http://php.net/manual/en/function.date.php for what the letters stand for + "ver" => "version", + "for" => "for", + "to" => "to", + "go" => "Go", + "yes" => "Yes", + "no" => "No", + "sql" => "SQL", + "csv" => "CSV", + "csv_tbl" => "Table that CSV pertains to", + "srch" => "Search", + "srch_again" => "Do Another Search", + "login" => "Log In", + "logout" => "Logout", + "view" => "View", // here, the noun SQL view is meant, not the verb "to view" + "confirm" => "Confirm", + "cancel" => "Cancel", + "save_as" => "Save As", + "options" => "Options", + "no_opt" => "No options", + "help" => "Help", + "installed" => "installed", + "not_installed" => "not installed", + "done" => "done", + "insert" => "Insert", + "export" => "Export", + "import" => "Import", + "rename" => "Rename", + "empty" => "Empty", + "drop" => "Drop", + "tbl" => "Table", + "chart" => "Chart", + "err" => "ERROR", + "act" => "Action", + "rec" => "Records", + "col" => "Column", + "cols" => "Columns", + "rows" => "row(s)", + "edit" => "Edit", + "del" => "Delete", + "add" => "Add", + "backup" => "Backup database file", + "before" => "Before", + "after" => "After", + "passwd" => "Password", + "passwd_incorrect" => "Incorrect password.", + "chk_ext" => "Checking supported SQLite PHP extensions", + "autoincrement" => "Autoincrement", + "not_null" => "Not NULL", + "attention" => "Attention", + "none" => "None", + "as_defined" => "As defined", + "expression" => "Expression", + "download" => "Download", + "open_in_browser" => "Open in browser", + + "sqlite_ext" => "SQLite extension", + "sqlite_ext_support" => "It appears that none of the supported SQLite library extensions are available in your installation of PHP. You may not use %s until you install at least one of them.", + "sqlite_v" => "SQLite version", + "sqlite_v_error" => "It appears that your database is of SQLite version %s but your installation of PHP does not contain the necessary extensions to handle this version. To fix the problem, either delete the database and allow %s to create it automatically or recreate it manually as SQLite version %s.", + "report_issue" => "The problem cannot be diagnosed properly. Please file an issue report at", + "sqlite_limit" => "Due to the limitations of SQLite, only the field name and data type can be modified.", + + "php_v" => "PHP version", + "new_version" => "There is a new version!", + + "db_dump" => "database dump", + "db_f" => "database file", + "db_ch" => "Change Database", + "db_event" => "Database Event", + "db_name" => "Database name", + "db_rename" => "Rename Database", + "db_renamed" => "Database '%s' has been renamed to", + "db_del" => "Delete Database", + "db_path" => "Path to database", + "db_size" => "Size of database", + "db_mod" => "Database last modified", + "db_create" => "Create New Database", + "db_vac" => "The database, '%s', has been VACUUMed.", + "db_not_writeable" => "The database, '%s', does not exist and cannot be created because the containing directory, '%s', is not writable. The application is unusable until you make it writable.", + "db_setup" => "There was a problem setting up your database, %s. An attempt will be made to find out what's going on so you can fix the problem more easily", + "db_exists" => "A database, other file or directory of the name '%s' already exists.", + "db_blank" => "The database name cannot be blank.", + + "exported" => "Exported", + "struct" => "Structure", + "struct_for" => "structure for", + "on_tbl" => "on table", + "data_dump" => "Data dump for", + "backup_hint" => "Hint: To backup your database, the easiest way is to %s.", + "backup_hint_linktext" => "download the database-file", + "total_rows" => "a total of %s rows", + "total" => "Total", + "not_dir" => "The directory you specified to scan for databases does not exist or is not a directory.", + "bad_php_directive" => "It appears that the PHP directive, 'register_globals' is enabled. This is bad. You need to disable it before continuing.", + "page_gen" => "Page generated in %s seconds.", + "powered" => "Powered by", + "free_software" => "This is free software.", + "please_donate" => "Please donate.", + "remember" => "Remember me", + "no_db" => "Welcome to %s. It appears that you have selected to scan a directory for databases to manage. However, %s could not find any valid SQLite databases. You may use the form below to create your first database.", + "no_db2" => "The directory you specified does not contain any existing databases to manage, and the directory is not writable. This means you can't create any new databases using %s. Either make the directory writable or manually upload databases to the directory.", + "dir_not_executable" => "The directory you specified cannot be scanned for databases as %s has no execute permissions on it. On Linux, use 'chmod +x %s' to fix this.", + + "create" => "Create", + "created" => "has been created", + "create_tbl" => "Create new table", + "create_tbl_db" => "Create new table on database", + "create_trigger" => "Creating new trigger on table", + "create_index" => "Creating new index on table", + "create_index1" => "Create Index", + "create_view" => "Create new view on database", + + "trigger" => "Trigger", + "triggers" => "Triggers", + "trigger_name" => "Trigger name", + "trigger_act" => "Trigger Action", + "trigger_step" => "Trigger Steps (semicolon terminated)", + "when_exp" => "WHEN expression (type expression without 'WHEN')", + "index" => "Index", + "indexes" => "Indexes", + "index_name" => "Index name", + "name" => "Name", + "unique" => "Unique", + "seq_no" => "Seq. No.", + "emptied" => "has been emptied", + "dropped" => "has been dropped", + "renamed" => "has been renamed to", + "altered" => "has been altered successfully", + "inserted" => "inserted", + "deleted" => "deleted", + "affected" => "affected", + "blank_index" => "Index name must not be blank.", + "one_index" => "You must specify at least one index column.", + "docu" => "Documentation", + "license" => "License", + "proj_site" => "Project Site", + "bug_report" => "This may be a bug that needs to be reported at", + "return" => "Return", + "browse" => "Browse", + "fld" => "Field", + "fld_num" => "Number of Fields", + "fields" => "Fields", + "type" => "Type", + "operator" => "Operator", + "val" => "Value", + "update" => "Update", + "comments" => "Comments", + + "specify_fields" => "You must specify the number of table fields.", + "specify_tbl" => "You must specify a table name.", + "specify_col" => "You must specify a column.", + + "tbl_exists" => "Table of the same name already exists.", + "show" => "Show", + "show_rows" => "Showing %s row(s). ", + "showing" => "Showing", + "showing_rows" => "Showing rows", + "query_time" => "(Query took %s sec)", + "syntax_err" => "There is a problem with the syntax of your query (Query was not executed)", + "run_sql" => "Run SQL query/queries on database '%s'", + "recent_queries" => "Recent Queries", + "full_texts" => "Show full texts", + "no_full_texts" => "Shorten long texts", + + "ques_empty" => "Are you sure you want to empty the table '%s'?", + "ques_drop" => "Are you sure you want to drop the table '%s'?", + "ques_drop_view" => "Are you sure you want to drop the view '%s'?", + "ques_del_rows" => "Are you sure you want to delete row(s) %s from table '%s'?", + "ques_del_db" => "Are you sure you want to delete the database '%s'?", + "ques_column_delete" => "Are you sure you want to delete column(s) %s from table '%s'?", + "ques_del_index" => "Are you sure you want to delete index '%s'?", + "ques_del_trigger" => "Are you sure you want to delete trigger '%s'?", + "ques_primarykey_add" => "Are you sure you want to add a primary key for the column(s) %s in table '%s'?", + + "export_struct" => "Export with structure", + "export_data" => "Export with data", + "add_drop" => "Add DROP TABLE", + "add_transact" => "Add TRANSACTION", + "fld_terminated" => "Fields terminated by", + "fld_enclosed" => "Fields enclosed by", + "fld_escaped" => "Fields escaped by", + "fld_names" => "Field names in first row", + "rep_null" => "Replace NULL by", + "rem_crlf" => "Remove CRLF characters within fields", + "put_fld" => "Put field names in first row", + "null_represent" => "NULL represented by", + "import_suc" => "Import was successful.", + "import_into" => "Import into", + "import_f" => "File to import", + "max_file_size" => "Maximum file size", + "rename_tbl" => "Rename table '%s' to", + + "rows_records" => "row(s) starting from record # ", + "rows_aff" => "row(s) affected. ", + + "as_a" => "as a", + "readonly_tbl" => "'%s' is a view, which means it is a SELECT statement treated as a read-only table. You may not edit or insert records.", + "chk_all" => "Check All", + "unchk_all" => "Uncheck All", + "with_sel" => "With Selected", + + "no_tbl" => "No table in database.", + "no_chart" => "If you can read this, it means the chart could not be generated. The data you are trying to view may not be appropriate for a chart.", + "no_rows" => "There are no rows in the table for the range you selected.", + "no_sel" => "You did not select anything.", + + "chart_type" => "Chart Type", + "chart_bar" => "Bar Chart", + "chart_pie" => "Pie Chart", + "chart_line" => "Line Chart", + "lbl" => "Labels", + "empty_tbl" => "This table is empty.", + "click" => "Click here", + "insert_rows" => "to insert rows.", + "restart_insert" => "Restart insertion with ", + "ignore" => "Ignore", + "func" => "Function", + "new_insert" => "Insert As New Row", + "save_ch" => "Save Changes", + "def_val" => "Default Value", + "prim_key" => "Primary Key", + "tbl_end" => "field(s) at end of table", + "query_used_table" => "Query used to create this table", + "query_used_view" => "Query used to create this view", + "create_index2" => "Create an index on", + "create_trigger2" => "Create a new trigger", + "new_fld" => "Adding new field(s) to table '%s'", + "add_flds" => "Add Fields", + "edit_col" => "Editing column '%s'", + "vac" => "Vacuum", + "vac_desc" => "Large databases sometimes need to be VACUUMed to reduce their footprint on the server. Click the button below to VACUUM the database '%s'.", + "vac_on_empty"=>"Rebuild database file to recover unused space (Vacuum)", + "event" => "Event", + "each_row" => "For Each Row", + "define_index" => "Define index properties", + "dup_val" => "Duplicate values", + "allow" => "Allowed", + "not_allow" => "Not Allowed", + "asc" => "Ascending", + "desc" => "Descending", + "warn0" => "You have been warned.", + "warn_passwd" => "You are using the default password, which can be dangerous. You can change it easily at the top of %s.", + "counting_skipped" => "Counting of records has been skipped for some tables because your database is comparably big and some tables don't have primary keys assigned to them so counting might be slow. Add a primary key to these tables or %sforce counting%s.", + "sel_state" => "Select Statement", + "delimit" => "Delimiter", + "back_top" => "Back to Top", + "choose_f" => "Choose File", + "instead" => "Instead of", + "define_in_col" => "Define index column(s)", + + "delete_only_managed" => "You can only delete databases managed by this tool!", + "rename_only_managed" => "You can only rename databases managed by this tool!", + "db_moved_outside" => "You either tried to move the database into a directory where it cannot be managed anylonger, or the check if you did this failed because of missing rights.", + "extension_not_allowed" => "The extension you provided is not within the list of allowed extensions. Please use one of the following extensions", + "add_allowed_extension" => "You can add extensions to this list by adding your extension to \$allowed_extensions in the configuration.", + "database_not_writable" => "The database-file is not writable, so its content cannot be changed in any way.", + "directory_not_writable" => "The database-file itself is writable, but to write into it, the containing directory needs to be writable as well. This is because SQLite puts temporary files in there for locking.", + "tbl_inexistent" => "Table %s does not exist", + "col_inexistent" => "Column %s does not exist", + + // errors that can happen when ALTER TABLE fails. You don't necessarily have to translate these. + "alter_failed" => "Altering of Table %s failed", + "alter_tbl_name_not_replacable" => "could not replace the table name with the temporary one", + "alter_no_def" => "no ALTER definition", + "alter_parse_failed" =>"failed to parse ALTER definition", + "alter_action_not_recognized" => "ALTER action could not be recognized", + "alter_no_add_col" => "no column to add detected in ALTER statement", + "alter_pattern_mismatch"=>"Pattern did not match on your original CREATE TABLE statement", + "alter_col_not_recognized" => "could not recognize new or old column name", + "alter_unknown_operation" => "Unknown ALTER operation!", + + /* Help documentation */ + "help_doc" => "Help Documentation", + "help1" => "SQLite Library Extensions", + "help1_x" => "%s uses PHP library extensions that allow interaction with SQLite databases. Currently, %s supports PDO, SQLite3, and SQLiteDatabase. Both PDO and SQLite3 deal with version 3 of SQLite, while SQLiteDatabase deals with version 2. So, if your PHP installation includes more than one SQLite library extension, PDO and SQLite3 will take precedence to make use of the better technology. However, if you have existing databases that are of version 2 of SQLite, %s will be forced to use SQLiteDatabase for only those databases. Not all databases need to be of the same version. During the database creation, however, the most advanced extension will be used.", + "help2" => "Creating a New Database", + "help2_x" => "When you create a new database, the name you entered will be appended with the appropriate file extension (.db, .db3, .sqlite, etc.) if you do not include it yourself. The database will be created in the directory you specified as the \$directory variable.", + "help3" => "Tables vs. Views", + "help3_x" => "On the main database page, there is a list of tables and views. Since views are read-only, certain operations will be disabled. These disabled operations will be apparent by their omission in the location where they should appear on the row for a view. If you want to change the data for a view, you need to drop that view and create a new view with the appropriate SELECT statement that queries other existing tables. For more information, see http://en.wikipedia.org/wiki/View_(database)", + "help4" => "Writing a Select Statement for a New View", + "help4_x" => "When you create a new view, you must write an SQL SELECT statement that it will use as its data. A view is simply a read-only table that can be accessed and queried like a regular table, except it cannot be modified through insertion, column editing, or row editing. It is only used for conveniently fetching data.", + "help5" => "Export Structure to SQL File", + "help5_x" => "During the process for exporting to an SQL file, you may choose to include the queries that create the table and columns.", + "help6" => "Export Data to SQL File", + "help6_x" => "During the process for exporting to an SQL file, you may choose to include the queries that populate the table(s) with the current records of the table(s).", + "help7" => "Add Drop Table to Exported SQL File", + "help7_x" => "During the process for exporting to an SQL file, you may choose to include queries to DROP the existing tables before adding them so that problems do not occur when trying to create tables that already exist.", + "help8" => "Add Transaction to Exported SQL File", + "help8_x" => "During the process for exporting to an SQL file, you may choose to wrap the queries around a TRANSACTION so that if an error occurs at any time during the importation process using the exported file, the database can be reverted to its previous state, preventing partially updated data from populating the database.", + "help9" => "Add Comments to Exported SQL File", + "help9_x" => "During the process for exporting to an SQL file, you may choose to include comments that explain each step of the process so that a human can better understand what is happening.", + "help10" => "Partial Indexes", + "help10_x" => "Partial indexes are indexes over a subset of the rows of a table specified by a WHERE clause. Note this requires at least SQLite 3.8.0 and database files with partial indexes won't be readable or writable by older versions. See the SQLite documentation.", + "help11" => "Maximum size of file uploads", + "help11_x" => "The maximum size of file uploads is determined by three PHP settings: upload_max_filesize, post_max_size and memory_limit. The smallest of these three limits the maximum size for file uploads. To upload larger files, adjust these values in your php.ini file." + +); + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//there is no reason for the average user to edit anything below this comment +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +//- Initialization + +// load optional configuration file +$config_filename = './phpliteadmin.config.php'; +if (is_readable($config_filename)) +{ + include_once $config_filename; +} + +//constants 1 +define("PROJECT", "phpLiteAdmin"); +define("VERSION", "1.9.8.2"); +define("FORCETYPE", false); //force the extension that will be used (set to false in almost all circumstances except debugging) +define("SYSTEMPASSWORD", $password); // Makes things easier. +define('PROJECT_URL','https://www.phpliteadmin.org/'); +define('DONATE_URL','https://www.phpliteadmin.org/donate/'); +define('VERSION_CHECK_URL','https://www.phpliteadmin.org/current_version.php'); +define('PROJECT_BUGTRACKER_LINK','https://bitbucket.org/phpliteadmin/public/issues?status=new&status=open'); +define('PROJECT_INSTALL_LINK','https://bitbucket.org/phpliteadmin/public/wiki/Installation'); + +// up here, we don't output anything. debug output might appear here which is catched by ob and thrown later +ob_start(); + +// Resource output (css and javascript files) +// we get out of the main code as soon as possible, without inizializing the session +if (isset($_GET['resource'])) +{ + Resources::output($_GET['resource']); + exit(); +} + +// don't mess with this - required for the login session +ini_set('session.cookie_httponly', '1'); +session_start(); + +// version-number added so after updating, old session-data is not used anylonger +// cookies names cannot contain symbols, except underscores +define("COOKIENAME", preg_replace('/[^a-zA-Z0-9_]/', '_', $cookie_name . '_' . VERSION) ); + +$params = new GetParameters(); + +if($debug==true) +{ + ini_set("display_errors", 1); + error_reporting(E_STRICT | E_ALL); +} else +{ + @ini_set("display_errors", 0); +} + +class MicroTimer { + + private $startTime, $stopTime; + + // creates and starts a timer + function __construct() + { + $this->startTime = microtime(true); + } + + // stops a timer + public function stop() + { + $this->stopTime = microtime(true); + } + + // returns the number of seconds from the timer's creation, or elapsed + // between creation and call to ->stop() + public function elapsed() + { + if ($this->stopTime) + return round($this->stopTime - $this->startTime, 4); + + return round(microtime(true) - $this->startTime, 4); + } + + // called when using a MicroTimer object as a string + public function __toString() + { + return (string) $this->elapsed(); + } + +} +// start the timer to record page load time +$pageTimer = new MicroTimer(); + +// load language file +if($language != 'en') { + $temp_lang=$lang; + if(is_file('languages/lang_'.$language.'.php')) + include('languages/lang_'.$language.'.php'); + elseif(is_file('lang_'.$language.'.php')) + include('lang_'.$language.'.php'); + $lang = array_merge($temp_lang, $lang); + unset($temp_lang); +} + +// stripslashes if MAGIC QUOTES is turned on +// This is only a workaround. Please better turn off magic quotes! +// This code is from http://php.net/manual/en/security.magicquotes.disabling.php +// if (get_magic_quotes_gpc()) { +// $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST); +// while (list($key, $val) = each($process)) { +// foreach ($val as $k => $v) { +// unset($process[$key][$k]); +// if (is_array($v)) { +// $process[$key][stripslashes($k)] = $v; +// $process[] = &$process[$key][stripslashes($k)]; +// } else { +// $process[$key][stripslashes($k)] = stripslashes($v); +// } +// } +// } +// unset($process); +// } + + +//data types array +$sqlite_datatypes = array("INTEGER", "REAL", "TEXT", "BLOB","NUMERIC","BOOLEAN","DATETIME"); + +//available SQLite functions array (don't add anything here or there will be problems) +$sqlite_functions = array("abs", "hex", "length", "lower", "ltrim", "random", "round", "rtrim", "trim", "typeof", "upper"); + +//- Support functions + +// for php < 5.6.0 +if(!function_exists('hash_equals')) +{ + function hash_equals($str1, $str2) + { + if(strlen($str1) != strlen($str2)) + return false; + else { + $res = $str1 ^ $str2; + $ret = 0; + for($i = strlen($res) - 1; $i >= 0; $i--) + $ret |= ord($res[$i]); + return !$ret; + } + } +} + +//function that allows SQL delimiter to be ignored inside comments or strings +function explode_sql($delimiter, $sql) +{ + $ign = array('"' => '"', "'" => "'", "/*" => "*/", "--" => "\n"); // Ignore sequences. + $out = array(); + $last = 0; + $slen = strlen($sql); + $dlen = strlen($delimiter); + $i = 0; + while($i < $slen) + { + // Split on delimiter + if($slen - $i >= $dlen && substr($sql, $i, $dlen) == $delimiter) + { + array_push($out, substr($sql, $last, $i - $last)); + $last = $i + $dlen; + $i += $dlen; + continue; + } + // Eat comments and string literals + foreach($ign as $start => $end) + { + $ilen = strlen($start); + if($slen - $i >= $ilen && substr($sql, $i, $ilen) == $start) + { + $i+=strlen($start); + $elen = strlen($end); + while($i < $slen) + { + if($slen - $i >= $elen && substr($sql, $i, $elen) == $end) + { + // SQL comment characters can be escaped by doubling the character. This recognizes and skips those. + if($start == $end && $slen - $i >= $elen*2 && substr($sql, $i, $elen*2) == $end.$end) + { + $i += $elen * 2; + continue; + } + else + { + $i += $elen; + continue 3; + } + } + $i++; + } + continue 2; + } + } + $i++; + } + if($last < $slen) + array_push($out, substr($sql, $last, $slen - $last)); + return $out; +} + +//function to scan entire directory tree and subdirectories +function dir_tree($dir) +{ + $path = array(); + $stack = array($dir); + while($stack) + { + $thisdir = array_pop($stack); + if($dircont = scandir($thisdir)) + { + $i=0; + while(isset($dircont[$i])) + { + if($dircont[$i] !== '.' && $dircont[$i] !== '..') + { + $current_file = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i]; + if(is_file($current_file)) + { + $path[] = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i]; + } + elseif (is_dir($current_file)) + { + $path[] = $thisdir.DIRECTORY_SEPARATOR.$dircont[$i]; + $stack[] = $current_file; + } + } + $i++; + } + } + } + return $path; +} + +//the function echo the help [?] links to the documentation +function helpLink($name) +{ + global $lang; + return "[?]"; +} + +// function to encode value into HTML just like htmlentities, but with adjusted default settings +function htmlencode($value, $flags=ENT_QUOTES, $encoding ="UTF-8") +{ + return htmlentities($value, $flags, $encoding); +} + +// reduce string chars +function subString($str) +{ + global $charsNum, $params; + if($charsNum > 10 && (!isset($params->fulltexts) || !$params->fulltexts) && mb_strlen($str)>$charsNum) + { + $str = mb_substr($str, 0, $charsNum).'...'; + } + return $str; +} + +// marks searchwords and htmlencodes correctly +function markSearchWords($input, $field, $search) +{ + $output = htmlencode($input); + if(isset($search['values'][$field]) && is_array($search['values'][$field])) + { + // build one regex that matches (all) search words + $regex = '/'; + $vali=0; + foreach($search['values'][$field] as $searchValue) + { + if($search['operators'][$field] =='LIKE' || $search['operators'][$field] == 'LIKE%') + $regex .= '(?:'.($searchValue[0]=='%'?'':'^'); // does the searchvalue have to occur at the start? + $regex .= preg_quote(trim($searchValue,'%'),'/'); // the search value + if($search['operators'][$field] =='LIKE' || $search['operators'][$field] == 'LIKE%') + $regex .= (substr($searchValue,-1)=='%'?'':'$').')'; // does the searchvalue have to occur at the end? + if($vali++ $betweenPart) + { + $output .= htmlencode($betweenPart); // part that does not match (might be empty) + if(isset($fldFoundParts[0][$index])) + $output .= ''.htmlencode($fldFoundParts[0][$index]).''; // the part that matched + } + } + return $output; +} + +// checks the (new) name of a database file +function checkDbName($name) +{ + global $allowed_extensions; + $info = pathinfo($name); + if(isset($info['extension']) && !in_array($info['extension'], $allowed_extensions)) + { + return false; + } else + { + return (!is_file($name) && !is_dir($name)); + } + +} + +// check whether a path is a db managed by this tool +// requires that $databases is already filled! +// returns the key of the db if managed, false otherwise. +function isManagedDB($path) +{ + global $databases; + foreach($databases as $db_key => $database) + { + if($path === $database['path']) + { + // a db we manage. Thats okay. + // return the key. + return $db_key; + } + } + // not a db we manage! + return false; +} + +// from a typename of a colun, get the type of the column's affinty +// see https://www.sqlite.org/datatype3.html section 2.1 for rules +function get_type_affinity($type) +{ + if (preg_match("/INT/i", $type)) + return "INTEGER"; + else if (preg_match("/(?:CHAR|CLOB|TEXT)/i", $type)) + return "TEXT"; + else if (preg_match("/BLOB/i", $type) || $type=="") + return "NONE"; + else if (preg_match("/(?:REAL|FLOA|DOUB)/i", $type)) + return "REAL"; + else + return "NUMERIC"; +} + + +// Returns a file size limit in bytes based on the PHP upload_max_filesize +// post_max_size and memory_limit. Returns -1 in case of no limit. +function fileUploadMaxSize() +{ + $max1 = parseSize(ini_get('post_max_size')); + $max2 = parseSize(ini_get('upload_max_filesize')); + $max3 = parseSize(ini_get('memory_limit')); + if($max1>0 && ($max1<=$max2 || $max2==0) && ($max1<=$max3 || $max3==-1)) + return $max1; + elseif($max2>0 && ($max2<=$max1 || $max1==0) && ($max2<=$max3 || $max3==-1)) + return $max2; + elseif($max3>-1 && ($max3<=$max1 || $max1==0) && ($max3<=$max2 || $max2==0)) + return $max3; + else + return -1; // no limit +} + +// Parses given size string like "12M" into number of bytes +// based on https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Utility%21Bytes.php/function/Bytes%3A%3AtoInt/8.2.x +function parseSize($size) +{ + // Remove the non-unit characters from the size. + $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); + // Remove the non-numeric characters from the size. + $size = preg_replace('/[^0-9\.]/', '', $size); + if ($unit) + { + // Find the position of the unit in the ordered string which is the power + // of magnitude to multiply a kilobyte by. + return round($size * pow(1024, stripos('bkmgtpezy', $unit[0]))); + } + else { + return round($size); + } +} + + +//- Check user authentication, login and logout +$auth = new Authorization(); //create authorization object + +// check if user has attempted to log out +if (isset($_GET['logout'])) + $auth->revoke(); +// check if user has attempted to log in +else if (isset($_POST['login']) && isset($_POST['password'])) +{ + $attempt = $auth->attemptGrant($_POST['password'], isset($_POST['remember'])); + $params->redirect( $attempt ? array():array('failed'=>'1') ); +} + +//- Actions on database files and bulk data +if ($auth->isAuthorized()) +{ + + //- Create a new database + if(isset($_POST['new_dbname'])) + { + if($_POST['new_dbname']=='') + $params->redirect(array('table'=>null), $lang['err'].': '.$lang['db_blank']); + else + { + $str = preg_replace('@[^\w\-.]@u','', $_POST['new_dbname']); + $dbname = $str; + $dbpath = $str; + if(checkDbName($dbname)) + { + $tdata = array(); + $tdata['name'] = $dbname; + $tdata['path'] = $directory.DIRECTORY_SEPARATOR.$dbpath; + if(isset($_POST['new_dbtype'])) + $tdata['type'] = $_POST['new_dbtype']; + else + $tdata['type'] = 3; + $td = new Database($tdata); + $td->query("VACUUM"); + } else + { + if(is_file($dbname) || is_dir($dbname)) + $params->redirect(array('view'=>'structure'),$lang['err'].': '.sprintf($lang['db_exists'], htmlencode($dbname))); + else + $params->redirect(array('view'=>'structure'),$lang['extension_not_allowed'].': '.implode(', ', array_map('htmlencode', $allowed_extensions)).'
'.$lang['add_allowed_extension']); + } + } + } + + //- Scan a directory for databases + if($directory!==false) + { + if($directory[strlen($directory)-1]==DIRECTORY_SEPARATOR) //if user has a trailing slash in the directory, remove it + $directory = substr($directory, 0, strlen($directory)-1); + + if(is_dir($directory)) //make sure the directory is valid + { + if($subdirectories===true) + $arr = dir_tree($directory); + else + $arr = scandir($directory); + $databases = array(); + $j = 0; + for($i=0; $i $database) + { + if($database['path'] === $tdata['path']) + { + $currentDB = $database; + $params->database = $database['path']; + break; + } + } + } + } + else //the directory is not valid - display error and exit + { + echo "
".$lang['not_dir']."
"; + exit(); + } + } + else + { + for($i=0; $idatabase = $databases[$db_key]['path']; + } + } + + //- Delete an existing database + if(isset($_GET['database_delete'])) + { + $dbpath = $_POST['database_delete']; + // check whether $dbpath really is a db we manage + $checkDB = isManagedDB($dbpath); + if($checkDB !== false) + { + unlink($dbpath); + unset($params->database); + unset($currentDB); + unset($databases[$checkDB]); + } else die($lang['err'].': '.$lang['delete_only_managed']); + } + + //- Rename an existing database + if(isset($_GET['database_rename'])) + { + $oldpath = $_POST['oldname']; + $newpath = $_POST['newname']; + $oldpath_parts = pathinfo($oldpath); + $newpath_parts = pathinfo($newpath); + // only rename? + $newpath = $oldpath_parts['dirname'].DIRECTORY_SEPARATOR.basename($_POST['newname']); + if($newpath != $_POST['newname'] && $subdirectories) + { + // it seems that the file should not only be renamed but additionally moved. + // we need to make sure it stays within $directory... + $new_realpath = realpath($newpath_parts['dirname']).DIRECTORY_SEPARATOR; + $directory_realpath = realpath($directory).DIRECTORY_SEPARATOR; + if(strpos($new_realpath, $directory_realpath)===0) + { + // its okay, the new directory is within $directory + $newpath = $_POST['newname']; + } + else $params->redirect(array('view'=>'rename'), $lang['err'].': '.$lang['db_moved_outside']); + } + + if(checkDbName($newpath)) + { + $checkDB = isManagedDB($oldpath); + if($checkDB !==false ) + { + rename($oldpath, $newpath); + $databases[$checkDB]['path'] = $newpath; + $databases[$checkDB]['name'] = basename($newpath); + $currentDB = $databases[$checkDB]; + $params->database = $databases[$checkDB]['path']; + $params->redirect(array('view'=>'rename'), sprintf($lang['db_renamed'], htmlencode($oldpath))." '".htmlencode($newpath)."'."); + } + else $params->redirect(array('view'=>'rename'), $lang['err'].': '.$lang['rename_only_managed']); + } + else + { + if(is_file($newpath) || is_dir($newpath)) + $params->redirect(array('view'=>'rename'), $lang['err'].": " . sprintf($lang['db_exists'], htmlencode($newpath))); + else + $params->redirect(array('view'=>'rename'), $lang['err'].": " . $lang['extension_not_allowed'].': '.implode(', ', array_map('htmlencode', $allowed_extensions)).'
'.$lang['add_allowed_extension']); + } + } + + + //- Export (download a dump) an existing database + if(isset($_POST['export'])) + { + ob_end_clean(); + $export_filename = str_replace(array("\r", "\n"), '',$_POST['filename']); // against http header injection (php < 5.1.2 only) + if($_POST['export_type']=="sql") + { + header('Content-Type: text/sql'); + header('Content-Disposition: attachment; filename="'.$export_filename.'.'.$_POST['export_type'].'";'); + if(isset($_POST['tables'])) + $tables = $_POST['tables']; + else + { + $tables = array(); + $tables[0] = $_POST['single_table']; + } + $drop = isset($_POST['drop']); + $structure = isset($_POST['structure']); + $data = isset($_POST['data']); + $transaction = isset($_POST['transaction']); + $comments = isset($_POST['comments']); + $db = new Database($currentDB); + echo $db->export_sql($tables, $drop, $structure, $data, $transaction, $comments); + } + else if($_POST['export_type']=="csv") + { + header("Content-type: application/csv"); + header('Content-Disposition: attachment; filename="'.$export_filename.'.'.$_POST['export_type'].'";'); + header("Pragma: no-cache"); + header("Expires: 0"); + if(isset($_POST['tables'])) + $tables = $_POST['tables']; + else + { + $tables = array(); + $tables[0] = $_POST['single_table']; + } + $field_terminate = $_POST['export_csv_fieldsterminated']; + $field_enclosed = $_POST['export_csv_fieldsenclosed']; + $field_escaped = $_POST['export_csv_fieldsescaped']; + $null = $_POST['export_csv_replacenull']; + $crlf = isset($_POST['export_csv_crlf']); + $fields_in_first_row = isset($_POST['export_csv_fieldnames']); + $db = new Database($currentDB); + echo $db->export_csv($tables, $field_terminate, $field_enclosed, $field_escaped, $null, $crlf, $fields_in_first_row); + } + exit(); + } + + //- Import a file into an existing database + if(isset($_POST['import'])) + { + $db = new Database($currentDB); + $db->registerUserFunction($custom_functions); + if($_POST['import_type']=="sql") + { + $data = file_get_contents($_FILES["file"]["tmp_name"]); + $importSuccess = $db->import_sql($data); + } + else + { + $field_terminate = $_POST['import_csv_fieldsterminated']; + $field_enclosed = $_POST['import_csv_fieldsenclosed']; + $field_escaped = $_POST['import_csv_fieldsescaped']; + $null = $_POST['import_csv_replacenull']; + $fields_in_first_row = isset($_POST['import_csv_fieldnames']); + if(isset($_POST['single_table']) && $_POST['single_table']!='') + $table = $_POST['single_table']; + else + { + $table = basename($_FILES["file"]["name"],".csv"); + $i=""; + while($db->getTypeOfTable($table.$i)!="") + { + if($i=="") + $i=2; + else + $i++; + } + $table = $table.$i; + } + $importSuccess = $db->import_csv($_FILES["file"]["tmp_name"], $table, $field_terminate, $field_enclosed, $field_escaped, $null, $fields_in_first_row); + } + } + //- Download (backup) a database file (as SQLite file, not as dump) + if(isset($_GET['download']) && isManagedDB($_GET['download'])!==false) + { + ob_end_clean(); + header("Content-type: application/octet-stream"); + header('Content-Disposition: attachment; filename="'.basename($_GET['download']).'";'); + header("Pragma: no-cache"); + header("Expires: 0"); + readfile($_GET['download']); + exit; + } + + //- Select database (from session or first available) + if(!isset($currentDB) && count($databases)>0) + { + //set the current database to the first existing one in the array (default) + $currentDB = reset($databases); + $params->database = $currentDB['path']; + } + + if(isset($currentDB)) + { + //- Open database (creates a Database object) + $db = new Database($currentDB); //create the Database object + $db->registerUserFunction($custom_functions); + } + + // collect parameters early, just once + $target_table = isset($_GET['table']) ? $_GET['table'] : null; + // are we working on a view? let's check once here + $target_table_type = !is_null($target_table) ? $db->getTypeOfTable($target_table) : null; + if(is_null($target_table_type) && !is_null($target_table)) + $params->redirect(array('table'=>null), $lang['err'].': '.sprintf($lang['tbl_inexistent'], htmlencode($target_table))); + $params->table = $target_table; + + // initialize / change fulltexts and numrows parameter + if(isset($_GET['fulltexts'])) + $params->fulltexts = ($_GET['fulltexts'] ? 1 : 0); + else + $params->fulltexts = 0; + + if(isset($_GET['numRows']) && intval($_GET['numRows'])>0) + $params->numRows = intval($_GET['numRows']); + else + $params->numRows = $rowsNum; + + //- Switch on $_GET['action'] for operations without output + if(isset($_GET['action']) && isset($_GET['confirm'])) + { + switch($_GET['action']) + { + //- Table actions + + //- Create table (=table_create) + case "table_create": + $num = intval($_POST['rows']); + $name = $_POST['tablename']; + $primary_keys = array(); + for($i=0; $i<$num; $i++) + { + if($_POST[$i.'_field']!="" && isset($_POST[$i.'_primarykey'])) + { + $primary_keys[] = $_POST[$i.'_field']; + } + } + $query = "CREATE TABLE ".$db->quote($name)." ("; + for($i=0; $i<$num; $i++) + { + if($_POST[$i.'_field']!="") + { + $query .= $db->quote($_POST[$i.'_field'])." "; + $query .= $_POST[$i.'_type']." "; + if(isset($_POST[$i.'_primarykey'])) + { + if(count($primary_keys)==1) + { + $query .= "PRIMARY KEY "; + if(isset($_POST[$i.'_autoincrement']) && $db->getType() != "SQLiteDatabase") + $query .= "AUTOINCREMENT "; + } + $query .= "NOT NULL "; + } + if(!isset($_POST[$i.'_primarykey']) && isset($_POST[$i.'_notnull'])) + $query .= "NOT NULL "; + if($_POST[$i.'_defaultoption']!='defined' && $_POST[$i.'_defaultoption']!='none' && $_POST[$i.'_defaultoption']!='expr') + $query .= "DEFAULT ".$_POST[$i.'_defaultoption']." "; + elseif($_POST[$i.'_defaultoption']=='expr') + $query .= "DEFAULT (".$_POST[$i.'_defaultvalue'].") "; + elseif(isset($_POST[$i.'_defaultvalue']) && $_POST[$i.'_defaultoption']=='defined') + { + $typeAffinity = get_type_affinity($_POST[$i.'_type']); + if(($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC") && is_numeric($_POST[$i.'_defaultvalue'])) + $query .= "DEFAULT ".$_POST[$i.'_defaultvalue']." "; + else + $query .= "DEFAULT ".$db->quote($_POST[$i.'_defaultvalue'])." "; + } + $query = substr($query, 0, -1); + $query .= ", "; + } + } + if (count($primary_keys)>1) + { + $compound_key = ""; + foreach ($primary_keys as $primary_key) + { + $compound_key .= ($compound_key=="" ? "" : ", ") . $db->quote($primary_key); + } + $query .= "PRIMARY KEY (".$compound_key."), "; + } + $query = substr($query, 0, -2); + $query .= ")"; + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['tbl']." '".htmlencode($_POST['tablename'])."' ".$lang['created'].".
".htmlencode($query).""; + $params->redirect(($result===false ? array() : array('action'=>'column_view', 'table'=>$name) ), $completed); + break; + + //- Empty table (=table_empty) + case "table_empty": + $query1 = "DELETE FROM ".$db->quote_id($_GET['table']).";"; + $result1 = $db->query($query1); + if($result1 === false) + $completed = $db->getError(true); + if(isset($_POST['vacuum']) && $_POST['vacuum']) + { + $query2 = "VACUUM;"; + $result2 = $db->query($query2); + } + else + $query2 = ""; + if($result1 !== false) + $completed = $lang['tbl']." '".htmlencode($_GET['table'])."' ".$lang['emptied'].".
".htmlencode($query1)."
".htmlencode($query2)."
"; + $params->redirect(($result1===false ? array() : array('action'=>'row_view') ), $completed); + break; + + //- Create view (=view_create) + case "view_create": + $query = "CREATE VIEW ".$db->quote($_POST['viewname'])." AS ".$_POST['select']; + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['view']." '".htmlencode($_POST['viewname'])."' ".$lang['created'].".
".htmlencode($query).""; + $params->redirect(($result===false ? array() : array('action'=>'column_view', 'table'=>$_POST['viewname']) ), $completed); + break; + + //- Drop table (=table_drop) + case "table_drop": + $query1 = "DROP TABLE ".$db->quote_id($_GET['table']).";"; + $result1=$db->query($query1); + if($result1 === false) + $completed = $db->getError(true); + if(isset($_POST['vacuum']) && $_POST['vacuum']) + { + $query2 = "VACUUM;"; + $result2 = $db->query($query2); + } + else + $query2 = ""; + if($result1 !== false) + { + $target_table = null; + $completed = $lang['tbl']." '".htmlencode($_GET['table'])."' ".$lang['dropped'].".
".htmlencode($query1)."
".htmlencode($query2)."
";; + } + $params->redirect(array('table'=>null), $completed); + break; + + //- Drop view (=view_drop) + case "view_drop": + $query = "DROP VIEW ".$db->quote_id($_POST['viewname']); + $result=$db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['view']." '".htmlencode($_POST['viewname'])."' ".$lang['dropped'].".
".htmlencode($query).""; + $params->redirect(array('table'=>null), $completed); + break; + + //- Rename table (=table_rename) + case "table_rename": + $query = "ALTER TABLE ".$db->quote_id($_GET['table'])." RENAME TO ".$db->quote($_POST['newname']); + $type = $db->getTypeOfTable($_GET['table']); + if($db->getVersion()==3 && $type=='table' // SQLite 3 can rename tables, not views + // In SQL(ite) table names are case-insensitve, so changing is not supported by SQLite. + // But table names are stored and displayed case sensitive, so we use the workaround for case sensitive renaming. + && !($_GET['table'] !== $_POST['newname'] && strtolower($_GET['table']) === strtolower($_POST['newname'])) + ) + $result = $db->query($query, true); + else + // Workaround can rename tables of sqlite2 and views of both sqlite versions. Can also do case sensitive renames. + $result = $db->query($query, false); + if($result === false) + $completed = $db->getError(true); + else + { + $completed = $lang['tbl']." '".htmlencode($_GET['table'])."' ".$lang['renamed']." '".htmlencode($_POST['newname'])."'.
".htmlencode($query).""; + $target_table = $_POST['newname']; + } + $params->redirect(array('action'=>'row_view', 'table'=>$_POST['newname']), $completed); + break; + + //- Search table (=table_search) + case "table_search": + $searchValues = array(); + $searchOperators = array(); + + $tableInfo = $db->getTableInfo($target_table); + $j = 0; + $whereExpr = array(); + for($i=0; $iquote_id($field)." ".$operator; + else{ + if($operator == "LIKE%"){ + $operator = "LIKE"; + if(!preg_match('/(^%)|(%$)/', $value)) $value = '%'.$value.'%'; + $searchValues[$field] = array($value); + $valueQuoted = $db->quote($value); + } + elseif($operator == 'IN' || $operator == 'NOT IN') + { + $value = trim($value, '() '); + $values = explode(',',$value); + $values = array_map('trim', $values, array_fill(0,count($values),' \'"')); + if($operator == 'IN') + $searchValues[$field] = $values; + $values = array_map(array($db, 'quote'), $values); + $valueQuoted = '(' .implode(', ', $values) . ')'; + } + else + { + $searchValues[$field] = array($value); + $valueQuoted = $db->quote($value); + } + $whereExpr[$j] = $db->quote_id($field)." ".$operator." ".$valueQuoted; + } + $j++; + } + } + $searchWhere = ''; + if(sizeof($whereExpr)>0) + { + $searchWhere .= " WHERE ".$whereExpr[0]; + for($i=1; $i $searchWhere, + 'values' => $searchValues, + 'operators' => $searchOperators + ); + $params->redirect(array('action'=>'table_search','search'=>$searchID)); + break; + + //- Row actions + + //- Create row (=row_create) + case "row_create": + $completed = ""; + $num = $_POST['newRows']; + $z = 0; + $error = false; + + $tableInfo = $db->getTableInfo($target_table); + + for($i=0; $i<$num; $i++) + { + if(!isset($_POST[$i.":ignore"])) + { + $query_cols = ""; + $query_vals = ""; + $all_default = true; + for($j=0; $jquote_id($tableInfo[$j]['name']).","; + + $function = $_POST["function_".$j][$i]; + if($function!="") + $query_vals .= $function."("; + if(preg_match('/^BLOB/', $type)) + $query_vals .= ':blobval'.$j; + elseif(($typeAffinity=="TEXT" || $typeAffinity=="NONE") && !$null) + $query_vals .= $db->quote($value); + elseif(($typeAffinity=="INTEGER" || $typeAffinity=="REAL"|| $typeAffinity=="NUMERIC") && $value=="") + $query_vals .= "NULL"; + elseif($null) + $query_vals .= "NULL"; + else + $query_vals .= $db->quote($value); + if($function!="") + $query_vals .= ")"; + $query_vals .= ","; + } + $query = "INSERT INTO ".$db->quote_id($target_table); + if(!$all_default) + { + $query_cols = substr($query_cols, 0, strlen($query_cols)-1); + $query_vals = substr($query_vals, 0, strlen($query_vals)-1); + + $query.=" (". $query_cols . ") VALUES (". $query_vals. ")"; + } else { + $query .= " DEFAULT VALUES"; + } + if(isset($blobFiles)) + { + // blob files need to be done using a prepared statement because the query size would be too large + $handle = $db->prepareQuery($query); + foreach($blobFiles as $j=>$filename) + $db->bindValue($handle, ':blobval'.$j, file_get_contents($filename), 'blob'); + + $result1 = $db->executePrepared($handle, false); + } + else + $result1 = $db->query($query); + if($result1===false) + $error = true; + $completed .= "".htmlencode($query)."
"; + $z++; + } + } + if($error) + $completed = $db->getError(true); + else + $completed = $z." ".$lang['rows']." ".$lang['inserted'].".

".$completed; + $params->redirect(array('action'=>'row_view'), $completed); + break; + + //- Delete row (=row_delete) + case "row_delete": + $pks = json_decode($_GET['pk']); + + $query = "DELETE FROM ".$db->quote_id($target_table)." WHERE (".$db->wherePK($target_table,json_decode($pks[0])).")"; + for($i=1; $iwherePK($target_table,json_decode($pks[$i])).")"; + } + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = sizeof($pks)." ".$lang['rows']." ".$lang['deleted'].".
".htmlencode($query).""; + $params->redirect(array('action'=>'row_view'), $completed); + break; + + //- Edit row (=row_edit) + case "row_edit": + $pks = json_decode($_GET['pk']); + $z = 0; + + $tableInfo = $db->getTableInfo($target_table); + + if(isset($_POST['new_row'])) + $completed = ""; + else + $completed = sizeof($pks)." ".$lang['rows']." ".$lang['affected'].".

"; + + for($i=0; $iquote_id($tableInfo[$j]['name']).' AS \'blob\' FROM '.$db->quote_id($target_table).' WHERE '.$db->wherePK($target_table, json_decode($pks[$i])); + $bl = $db->select($select); + $blobFiles[$j] = $bl['blob']; + unset($bl); + } + else + { + if($_FILES[$i.":".$j]["error"] == UPLOAD_ERR_OK && is_file($_FILES[$i.":".$j]["tmp_name"])) + $blobFiles[$j] = file_get_contents($_FILES[$i.":".$j]["tmp_name"]); + else + $blobFiles[$j] = null; + } + } + else + $value = $_POST[$j][$i]; + } + else + $value = ""; + if(!preg_match('/^BLOB/', $type) && $value===$tableInfo[$j]['dflt_value']) + { + // if the value is the default value, skip it + continue; + } + $all_default = false; + $query_cols .= $db->quote_id($tableInfo[$j]['name']).","; + + $function = $_POST["function_".$j][$i]; + if($function!="") + $query_vals .= $function."("; + + if(preg_match('/^BLOB/', $type)) + $query_vals .= ':blobval'.$j; + elseif(($typeAffinity=="TEXT" || $typeAffinity=="NONE") && !$null) + $query_vals .= $db->quote($value); + elseif(($typeAffinity=="INTEGER" || $typeAffinity=="REAL"|| $typeAffinity=="NUMERIC") && $value=="") + $query_vals .= "NULL"; + elseif($null) + $query_vals .= "NULL"; + else + $query_vals .= $db->quote($value); + if($function!="") + $query_vals .= ")"; + $query_vals .= ","; + } + $query = "INSERT INTO ".$db->quote_id($target_table); + if(!$all_default) + { + $query_cols = substr($query_cols, 0, strlen($query_cols)-1); + $query_vals = substr($query_vals, 0, strlen($query_vals)-1); + + $query.=" (". $query_cols . ") VALUES (". $query_vals. ")"; + } else { + $query .= " DEFAULT VALUES"; + } + + if(isset($blobFiles)) + { + // blob files need to be done using a prepared statement because the query size would be too large + $handle = $db->prepareQuery($query); + foreach($blobFiles as $j=>$blobval) + $db->bindValue($handle, ':blobval'.$j, $blobval, 'blob'); + + $result1 = $db->executePrepared($handle, false); + } + else + $result1 = $db->query($query); + if($result1===false) + $error = true; + $z++; + } + else + { + $query = "UPDATE ".$db->quote_id($target_table)." SET "; + for($j=0; $jquote_id($tableInfo[$j]['name'])."="; + if($function!="") + $query .= $function."("; + if($null) + $query .= "NULL"; + else + { + if(preg_match('/^BLOB/', $type)) + $query .= ':blobval'.$j; + else + $query .= $db->quote($_POST[$j][$i]); + } + if($function!="") + $query .= ")"; + $query .= ", "; + } + $query = substr($query, 0, -2); + $query .= " WHERE ".$db->wherePK($target_table, json_decode($pks[$i])); + if(isset($blobFiles)) + { + // blob files need to be done using a prepared statement because the query size would be too large + $handle = $db->prepareQuery($query); + foreach($blobFiles as $j=>$filename) + $db->bindValue($handle, ':blobval'.$j, file_get_contents($filename), 'blob'); + + $result1 = $db->executePrepared($handle, false); + } + else + $result1 = $db->query($query); + if($result1===false) + { + $error = true; + } + } + $completed .= "".htmlencode($query)."
"; + } + if($error) + $completed = $db->getError(true); + elseif(isset($_POST['new_row'])) + $completed = $z." ".$lang['rows']." ".$lang['inserted'].".

".$completed; + $params->redirect(array('action'=>'row_view'), $completed); + break; + + + case "row_get_blob": + $blobVal = $db->select("SELECT ".$db->quote_id($_GET['column'])." AS 'blob' FROM ".$db->quote_id($target_table)." WHERE ".$db->wherePK($target_table, json_decode($_GET['pk']))); + $filename = 'download'; + if(function_exists('getimagesizefromstring')) // introduced in PHP 5.4.0 + $imagesize = getimagesizefromstring($blobVal['blob']); + if(isset($imagesize) && $imagesize!==false && isset($imagesize['mime'])) + $mimetype = $imagesize['mime']; + elseif(class_exists('finfo')) // included since php 5.3.0, but might be disabled on Windows + { + $finfo = new finfo(FILEINFO_MIME); + $mimetype = $finfo->buffer($blobVal['blob']); + } + else + $mimetype = "application/octet-stream"; + + if(isset($imagesize) && $imagesize!==false && isset($imagesize[2])) + $extension = image_type_to_extension($imagesize[2]); + else + $extension = '.blob'; + ob_end_clean(); + header('Content-Length: '.strlen($blobVal['blob'])); + header("Content-type: ".$mimetype); + if(isset($_GET['download_blob']) && $_GET['download_blob']) + header('Content-Disposition: attachment; filename="'.$filename.$extension.'";'); + header("Pragma: no-cache"); + header("Expires: 0"); + echo $blobVal['blob']; + exit; + break; + + + //- Column actions + + //- Create column (=column_create) + case "column_create": + $num = intval($_POST['rows']); + for($i=0; $i<$num; $i++) + { + if($_POST[$i.'_field']!="") + { + $query = "ALTER TABLE ".$db->quote_id($target_table)." ADD ".$db->quote($_POST[$i.'_field'])." "; + $query .= $_POST[$i.'_type']." "; + if(isset($_POST[$i.'_primarykey'])) + $query .= "PRIMARY KEY "; + if(isset($_POST[$i.'_notnull'])) + $query .= "NOT NULL "; + if($_POST[$i.'_defaultoption']!='defined' && $_POST[$i.'_defaultoption']!='none' && $_POST[$i.'_defaultoption']!='expr') + $query .= "DEFAULT ".$_POST[$i.'_defaultoption']." "; + elseif($_POST[$i.'_defaultoption']=='expr') + $query .= "DEFAULT (".$_POST[$i.'_defaultvalue'].") "; + elseif(isset($_POST[$i.'_defaultvalue']) && $_POST[$i.'_defaultoption']=='defined') + { + $typeAffinity = get_type_affinity($_POST[$i.'_type']); + if(($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC") && is_numeric($_POST[$i.'_defaultvalue'])) + $query .= "DEFAULT ".$_POST[$i.'_defaultvalue']." "; + else + $query .= "DEFAULT ".$db->quote($_POST[$i.'_defaultvalue'])." "; + } + if($db->getVersion()==3 && + ($_POST[$i.'_defaultoption']=='defined' || $_POST[$i.'_defaultoption']=='none' || $_POST[$i.'_defaultoption']=='NULL') + // Sqlite3 cannot add columns with default values that are not constant + && !isset($_POST[$i.'_primarykey']) + // sqlite3 cannot add primary key columns + && (!isset($_POST[$i.'_notnull']) || $_POST[$i.'_defaultoption']!='none') + // SQLite3 cannot add NOT NULL columns without DEFAULT even if the table is empty + ) + // use SQLITE3 ALTER TABLE ADD COLUMN + $result = $db->query($query, true); + else + // use ALTER TABLE workaround + $result = $db->query($query, false); + if($result===false) + $error = true; + } + } + if($error) + $completed = $db->getError(true); + else + $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered']."."; + $params->redirect(array('action'=>'column_view'), $completed); + break; + + //- Delete column (=column_delete) + case "column_delete": + $pks = explode(":", $_GET['pk']); + $query = "ALTER TABLE ".$db->quote_id($target_table).' DROP '.$db->quote_id($pks[0]); + for($i=1; $iquote_id($pks[$i]); + } + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered']."."; + $params->redirect(array('action'=>'column_view'), $completed); + break; + + //- Add a primary key (=primarykey_add) + case "primarykey_add": + $pks = explode(":", $_GET['pk']); + $query = "ALTER TABLE ".$db->quote_id($target_table).' ADD PRIMARY KEY ('.$db->quote_id($pks[0]); + for($i=1; $iquote_id($pks[$i]); + } + $query .= ")"; + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered']."."; + $params->redirect(array('action'=>'column_view'), $completed); + break; + + //- Edit column (=column_edit) + case "column_edit": + $query = "ALTER TABLE ".$db->quote_id($target_table).' CHANGE '.$db->quote_id($_POST['oldvalue'])." ".$db->quote($_POST['0_field'])." ".$_POST['0_type']; + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['tbl']." '".htmlencode($target_table)."' ".$lang['altered']."."; + $params->redirect(array('action'=>'column_view'), $completed); + break; + + //- Delete trigger (=trigger_delete) + case "trigger_delete": + $query = "DROP TRIGGER ".$db->quote_id($_GET['pk']); + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['trigger']." '".htmlencode($_GET['pk'])."' ".$lang['deleted'].".
".htmlencode($query).""; + $params->redirect(array('action'=>'column_view'), $completed); + break; + + //- Delete index (=index_delete) + case "index_delete": + $query = "DROP INDEX ".$db->quote_id($_GET['pk']); + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['index']." '".htmlencode($_GET['pk'])."' ".$lang['deleted'].".
".htmlencode($query).""; + $params->redirect(array('action'=>'column_view'), $completed); + break; + + //- Create trigger (=trigger_create) + case "trigger_create": + $str = "CREATE TRIGGER ".$db->quote($_POST['trigger_name']); + if($_POST['beforeafter']!="") + $str .= " ".$_POST['beforeafter']; + $str .= " ".$_POST['event']." ON ".$db->quote_id($target_table); + if(isset($_POST['foreachrow'])) + $str .= " FOR EACH ROW"; + if($_POST['whenexpression']!="") + $str .= " WHEN ".$_POST['whenexpression']; + $str .= " BEGIN"; + $str .= " ".$_POST['triggersteps']; + $str .= " END"; + $query = $str; + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['trigger']." ".$lang['created'].".
".htmlencode($query).""; + $params->redirect(array('action'=>'column_view'), $completed); + break; + + //- Create index (=index_create) + case "index_create": + $num = $_POST['num']; + if($_POST['name']=="") + { + $completed = $lang['blank_index']; + } + else if($_POST['0_field']=="") + { + $completed = $lang['one_index']; + } + else + { + $str = "CREATE "; + if($_POST['duplicate']=="no") + $str .= "UNIQUE "; + $str .= "INDEX ".$db->quote($_POST['name'])." ON ".$db->quote_id($target_table)." ("; + $str .= $db->quote_id($_POST['0_field']).$_POST['0_order']; + for($i=1; $i<$num; $i++) + { + if($_POST[$i.'_field']!="") + $str .= ", ".$db->quote_id($_POST[$i.'_field']).$_POST[$i.'_order']; + } + $str .= ")"; + if(isset($_POST['where']) && $_POST['where']!='') + $str.=" WHERE ".$_POST['where']; + $query = $str; + $result = $db->query($query); + if($result === false) + $completed = $db->getError(true); + else + $completed = $lang['index']." ".$lang['created'].".
".htmlencode($query).""; + } + $params->redirect(array('action'=>'column_view'), $completed); + break; + } + } +} + +// if not in debug mode, destroy all output until here +if($debug) + $bufferedOutput = ob_get_contents(); +ob_end_clean(); + +//- HTML: output starts here +header('Content-Type: text/html; charset=utf-8'); +?> + + + + + + +<?php echo PROJECT ?> + +", PHP_EOL; +else + // only use the default stylesheet if an external one does not exist + echo "", PHP_EOL; + +// HTML: output help text, then exit +if(isset($_GET['help'])) +{ + //help section array + $help = array($lang['help1'] => sprintf($lang['help1_x'], PROJECT, PROJECT, PROJECT)); + for($i=2; isset($lang['help'.$i]); $i++) + $help[$lang['help'.$i]]=$lang['help'.$i.'_x']; + ?> + + +
+ "; + echo "".PROJECT." v".VERSION." ".$lang['help_doc']."

"; + foreach((array)$help as $key => $val) + { + echo "".$key."
"; + } + echo "
"; + echo "

"; + foreach((array)$help as $key => $val) + { + echo "
"; + echo "".$key.""; + echo "
"; + echo $val; + echo "
"; + echo "".$lang['back_top'].""; + echo "
"; + } + ?> + + + + isAuthorized()) +{ + //- Javascript include + ?> + + + + + + + + + + + + + + +".$lang['bad_php_directive'].""; + echo ""; + exit(); +} + +//- HTML: login screen if not authorized, exit +if(!$auth->isAuthorized()) +{ + echo "
"; + echo "

v".VERSION."

"; + echo "
"; + if (isset($_GET['failed'])) + echo "".$lang['passwd_incorrect']."

"; + echo $params->getForm(); + echo $lang['passwd'].":
"; + echo "

"; + echo ""; + echo ""; + echo ""; + echo "
"; + echo "
"; + echo "
"; + echo "
"; + echo "".$lang['powered']." ".PROJECT." | "; + printf($lang['page_gen'], $pageTimer); + echo "
"; + echo ""; + exit(); +} + +//- User is authorized, display the main application + +if(count($databases)==0) // the database array is empty, offer to create a new database +{ + //- HTML: form to create a new database, exit + if($directory!==false && is_writable($directory)) + { + echo "
"; + printf($lang['no_db'], PROJECT, PROJECT); + echo "
"; + //if the user has performed some action, show the resulting message + if(isset($_GET['message']) && isset($_SESSION[COOKIENAME.'messages'][$_GET['message']])) + { + echo "
"; + echo $_SESSION[COOKIENAME.'messages'][$_GET['message']]; + echo "

"; + unset($_SESSION[COOKIENAME.'messages'][$_GET['message']]); + } + echo "
".$lang['db_create'].""; + echo $params->getForm(array('table'=>null), 'post', false, 'create_database'); + echo " "; + if(class_exists('SQLiteDatabase') && (class_exists('SQLite3') || class_exists('PDO'))) + { + echo ""; + } + echo ""; + echo ""; + echo "
"; + } + elseif(($directory!==false && !is_executable($directory))) + { + echo "
"; + echo $lang['err'].": ".sprintf($lang['dir_not_executable'], PROJECT, $directory); + echo "

"; + } + else + { + echo "
"; + echo $lang['err'].": ".sprintf($lang['no_db2'], PROJECT); + echo "

"; + } + exit(); +} + +//- HTML: sidebar +echo '
'; +echo "
"; +echo "

"; +echo " v".VERSION.""; +echo "

"; +echo ""; + +//- HTML: database list +$db->print_db_list(); +echo "
"; +echo "null))."'"; +if (!$target_table) + echo " class='active_table'"; +$name = $currentDB['name']; +if(strlen($name)>25) + $name = "...".substr($name, strlen($name)-22, 22); +echo ">".htmlencode($name).""; +echo ""; + +//- HTML: table list +$tables = $db->getTables(true, false); +foreach($tables as $tableName => $tableType) +{ + echo ""; + echo $params->getLink(array('action'=>'column_view', 'table'=>$tableName), "[".$lang[$tableType=='table'?'tbl':'view']."]"); + echo " "; + echo $params->getLink(array('action'=>'row_view', 'table'=>$tableName), htmlencode($tableName), + ($target_table == $tableName ? 'active_table' : '') ); + echo "
"; +} +if(count($tables)==0) + echo $lang['no_tbl']; +echo "
"; + +//- HTML: form to create a new database +if($directory!==false && is_writable($directory)) +{ + echo "
".$lang['db_create']." ".helpLink($lang['help2']).""; + echo $params->getForm(array('table'=>null), 'post', false, 'create_database'); + echo ""; + if(class_exists('SQLiteDatabase') && (class_exists('SQLite3') || class_exists('PDO'))) + { + echo ""; + } + echo ""; + echo ""; + echo "
"; +} + +echo "
"; +echo $params->getForm(array(),'get'); +echo ""; +echo ""; +echo "
"; +echo "
"; +echo '
'; + +//- HTML: breadcrumb navigation +echo $params->getLink(array('table'=>null), htmlencode($currentDB['name'])); +if ($target_table) + echo " → ".$params->getLink(array('action'=>'row_view'), htmlencode($target_table)); +echo "

"; + +//- Show the various tab views for a table +if($target_table) +{ + //- HTML: tabs + echo $params->getLink(array('action'=>'row_view'), $lang['browse'], + (in_array($_GET['action'], array('row_view', 'row_editordelete') ) ? 'tab_pressed' : 'tab')); + + echo $params->getLink(array('action'=>'column_view'), $lang['struct'], + (in_array($_GET['action'], array('column_view', 'column_edit', 'column_confirm', 'primarykey_add', 'column_create', 'index_create', 'index_delete', 'trigger_create', 'trigger_delete') ) ? 'tab_pressed' : 'tab')); + + echo $params->getLink(array('action'=>'table_sql'), $lang['sql'], + ($_GET['action']=="table_sql" ? 'tab_pressed' : 'tab')); + + echo $params->getLink(array( + 'action' => 'table_search', + 'oldSearch' => (isset($_GET['search'])?$_GET['search']:null) + ), $lang['srch'], ($_GET['action']=="table_search" ? 'tab_pressed' : 'tab')); + + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('action'=>'row_create'), $lang['insert'], + ($_GET['action']=="row_create" ? 'tab_pressed' : 'tab')); + + echo $params->getLink(array('action'=>'table_export'), $lang['export'], + ($_GET['action']=="table_export" ? 'tab_pressed' : 'tab')); + + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('action'=>'table_import'), $lang['import'], + ($_GET['action']=="table_import" ? 'tab_pressed' : 'tab')); + + if($db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('action'=>'table_rename'), $lang['rename'], + ($_GET['action']=="table_rename" ? 'tab_pressed' : 'tab')); + + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + { + echo $params->getLink(array('action'=>'table_empty'), $lang['empty'], + ($_GET['action']=="table_empty" ? 'tab_pressed empty' : 'tab empty')); + + echo $params->getLink(array('action'=>'table_drop'), $lang['drop'], + ($_GET['action']=="table_drop" ? 'tab_pressed drop' : 'tab drop')); + } elseif($db->isWritable() && $db->isDirWritable()) { + echo $params->getLink(array('action'=>'view_drop'), $lang['drop'], + ($_GET['action']=="view_drop" ? 'tab_pressed drop' : 'tab drop')); + } +} +else +//- Show the various tab views for a database +{ + $view = isset($_GET['view']) ? $_GET['view'] : 'structure'; + + echo $params->getLink(array('view'=>'structure'), $lang['struct'], ($view=="structure" ? 'tab_pressed': 'tab') ); + + echo $params->getLink(array('view'=>'sql'), $lang['sql'], ($view=="sql" ? 'tab_pressed': 'tab') ); + + echo $params->getLink(array('view'=>'export'), $lang['export'], ($view=="export" ? 'tab_pressed': 'tab') ); + + if($db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('view'=>'import'), $lang['import'], ($view=="import" ? 'tab_pressed': 'tab') ); + + if($db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('view'=>'vacuum'), $lang['vac'], ($view=="vacuum" ? 'tab_pressed': 'tab') ); + + if($directory!==false && is_writable($directory)) + { + + echo $params->getLink(array('view'=>'rename'), $lang['db_rename'], ($view=="rename" ? 'tab_pressed': 'tab') ); + + echo $params->getLink(array('view'=>'delete'), "".$lang['db_del']."", ($view=="delete" ? 'tab_pressed delete_db': 'tab delete_db') ); + } +} + +echo "
"; +echo "
"; + +//- HTML: confirmation panel +//if the user has performed some action, show the resulting message +if(isset($_GET['message']) && isset($_SESSION[COOKIENAME.'messages'][$_GET['message']])) +{ + echo "
"; + echo $_SESSION[COOKIENAME.'messages'][$_GET['message']]; + echo "

"; + unset($_SESSION[COOKIENAME.'messages'][$_GET['message']]); +} + + +//- Switch on $_GET['action'] for operations with output +if(isset($_GET['action']) && !isset($_GET['confirm'])) +{ + switch($_GET['action']) + { + //- Table actions + + //- Create table (=table_create) + case "table_create": + $query = "SELECT name FROM sqlite_master WHERE type='table' AND name=".$db->quote($_GET['tablename']); + $results = $db->selectArray($query); + if(sizeof($results)>0) + $exists = true; + else + $exists = false; + echo "

".$lang['create_tbl'].": '".htmlencode($_GET['tablename'])."'

"; + if($_GET['tablefields']=="" || intval($_GET['tablefields'])<=0) + echo $lang['specify_fields']; + else if($_GET['tablename']=="") + echo $lang['specify_tbl']; + else if($exists) + echo $lang['tbl_exists']; + else + { + $num = intval($_GET['tablefields']); + $name = $_GET['tablename']; + echo $params->getForm(array('action'=>'table_create', 'confirm'=>'1')); + echo ""; + echo ""; + echo ""; + echo ""; + $headings = array($lang['fld'], $lang['type'], $lang['prim_key']); + if($db->getType() != "SQLiteDatabase") $headings[] = $lang['autoincrement']; + $headings[] = $lang['not_null']; + $headings[] = $lang['def_val']; + for($k=0; $k" . $headings[$k] . ""; + echo ""; + + for($i=0; $i<$num; $i++) + { + $tdWithClass = ""; + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + if($db->getType() != "SQLiteDatabase") + { + echo $tdWithClass; + echo ""; + echo ""; + } + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + echo ""; + echo ""; + } + echo ""; + echo ""; + echo ""; + echo "
"; + echo "
"; + echo " "; + echo $params->getLink(array(), $lang['cancel']); + echo "
"; + echo ""; + if($db->getType() != "SQLiteDatabase") echo ""; + } + break; + + //- Perform SQL query on table (=table_sql) + case "table_sql": + if(isset($_POST['query']) && $_POST['query']!="") + { + $delimiter = $_POST['delimiter']; + $queryStr = $_POST['queryval']; + //save the queries in history if necessary + if($maxSavedQueries!=0 && $maxSavedQueries!=false) + { + if(!isset($_SESSION[COOKIENAME.'query_history'])) + $_SESSION[COOKIENAME.'query_history'] = array(); + $_SESSION[COOKIENAME.'query_history'][md5(strtolower($queryStr))] = $queryStr; + if(sizeof($_SESSION[COOKIENAME.'query_history']) > $maxSavedQueries) + array_shift($_SESSION[COOKIENAME.'query_history']); + } + $query = explode_sql($delimiter, $queryStr); //explode the query string into individual queries based on the delimiter + + for($i=0; $iquery($query[$i]); + + echo "
"; + echo "".htmlencode($query[$i]).""; + if($table_result === NULL || $table_result === false) + { + echo "
".$lang['err'].": ".htmlencode($db->getError())."
"; + } + echo "

"; + if($row = $db->fetch($table_result, 'num')) + { + for($j=0; $jgetColumnName($table_result,$j); + echo ""; + echo ""; + for($j=0; $j"; + echo htmlencode($headers[$j]); + echo ""; + } + echo ""; + $rowCount = 0; + for(; $rowCount==0 || $row = $db->fetch($table_result, 'num'); $rowCount++) + { + $tdWithClass = ""; + for($z=0; $zNULL"; + else + echo htmlencode(subString($row[$z])); + echo ""; + } + echo ""; + } + $queryTimer->stop(); + echo "
"; + echo "


"; + + + if($table_result !== NULL && $table_result !== false) + { + echo "
"; + if($rowCount>0 || $db->getAffectedRows()==0) + { + printf($lang['show_rows'], $rowCount); + } + if($db->getAffectedRows()>0 || $rowCount==0) + { + echo $db->getAffectedRows()." ".$lang['rows_aff']." "; + } + printf($lang['query_time'], $queryTimer); + echo "
"; + } + + + } + } + } + } + else + { + $delimiter = ";"; + $queryStr = "SELECT * FROM ".$db->quote_id($target_table)." WHERE 1"; + } + + echo "
"; + echo "".sprintf($lang['run_sql'],htmlencode($db->getName())).""; + echo $params->getForm(array('action'=>'table_sql')); + if(isset($_SESSION[COOKIENAME.'query_history']) && sizeof($_SESSION[COOKIENAME.'query_history'])>0) + { + echo "".$lang['recent_queries']."
    "; + foreach($_SESSION[COOKIENAME.'query_history'] as $key => $value) + echo "
  • ".htmlencode($value)."
  • "; + echo "


"; + } + echo "
"; + echo ""; + echo ""; + echo "
"; + echo "
"; + echo $lang['fields']."
"; + echo ""; + echo ""; + echo "
"; + echo "
"; + echo $lang['delimit']." "; + echo ""; + echo ""; + echo "
"; + break; + + //- Empty table (=table_empty) + case "table_empty": + echo $params->getForm(array('action'=>'table_empty','confirm'=>'1')); + echo "
"; + echo sprintf($lang['ques_empty'], htmlencode($target_table))."

"; + echo " ".$lang['vac_on_empty']."

"; + echo " "; + echo $params->getLink(array('table'=>null), $lang['cancel']); + echo "
"; + break; + + //- Drop table (=table_drop) + case "table_drop": + echo $params->getForm(array('action'=>'table_drop','confirm'=>'1')); + echo "
"; + echo sprintf($lang['ques_drop'], htmlencode($target_table))."

"; + echo " ".$lang['vac_on_empty']."

"; + echo " "; + echo $params->getLink(array('table'=>null), $lang['cancel']); + echo "
"; + break; + + //- Drop view (=view_drop) + case "view_drop": + echo $params->getForm(array('action'=>'view_drop','confirm'=>'1')); + echo ""; + echo "
"; + echo sprintf($lang['ques_drop_view'], htmlencode($target_table))."

"; + echo " "; + echo $params->getLink(array('table'=>null), $lang['cancel']); + echo "
"; + break; + + //- Export table (=table_export) + case "table_export": + echo $params->getForm(); + echo "
".$lang['export'].""; + echo ""; + echo ""; + echo "
"; + echo "
"; + + echo "
".$lang['options'].""; + echo " ".helpLink($lang['help5'])."
"; + echo " ".helpLink($lang['help6'])."
"; + echo " ".helpLink($lang['help7'])."
"; + echo " ".helpLink($lang['help8'])."
"; + echo " ".helpLink($lang['help9'])."
"; + echo "
"; + + echo ""; + + echo "
"; + echo "

"; + echo "
".$lang['save_as'].""; + $file = pathinfo($db->getPath()); + $name = $file['filename']; + echo " "; + echo "
"; + echo ""; + echo "
".sprintf($lang['backup_hint'], + $params->getLink(array('download' => $currentDB['path'], 'token' => $_SESSION[COOKIENAME.'token']), $lang["backup_hint_linktext"], '', $lang['backup']))."
"; + break; + + //- Import table (=table_import) + case "table_import": + if(isset($_POST['import'])) + { + echo "
"; + if($importSuccess===true) + echo $lang['import_suc']; + else + echo $lang['err'].': '.htmlencode($importSuccess); + echo "

"; + } + echo $params->getForm(array('action' => 'table_import'), 'post', true); + echo "
".$lang['import_into']." ".htmlencode($target_table).""; + echo ""; + echo "
"; + echo "
"; + + echo "
".$lang['options'].""; + echo $lang['no_opt']; + echo "
"; + + echo ""; + + echo "
"; + echo "

"; + + echo "
".$lang['import_f'].""; + echo "".$lang['max_file_size'].": ".number_format(fileUploadMaxSize()/1024/1024)." MiB ".helpLink($lang['help11'])."
"; + echo ""; + echo ""; + echo "
"; + break; + + //- Rename table (=table_rename) + case "table_rename": + echo $params->getForm(array('action'=>'table_rename', 'confirm'=>'1')); + printf($lang['rename_tbl'], htmlencode($target_table)); + echo " "; + echo ""; + break; + + //- Search table (=table_search) + case "table_search": + if(!isset($_GET['search'])) + { + $tableInfo = $db->getTableInfo($target_table); + + echo $params->getForm(array('action'=>'table_search', 'confirm'=>'1')); + + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + for($i=0; $i"; + $tdWithClassLeft = ""; + echo $tdWithClassLeft; + echo htmlencode($field); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($type); + echo ""; + echo $tdWithClassLeft; + echo ""; + echo ""; + echo $tdWithClassLeft; + if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC") + echo ""; + else + echo ""; + echo ""; + echo ""; + } + echo ""; + echo ""; + echo ""; + echo "
".$lang['fld']."".$lang['type']."".$lang['operator']."".$lang['val']."
"; + if(isset($_GET['oldSearch']) && isset($_SESSION[COOKIENAME.'search'][$_GET['oldSearch']]['values'][$field])) + $value = implode($_SESSION[COOKIENAME.'search'][$_GET['oldSearch']]['values'][$field], ","); + else + $value = ''; + if(isset($_GET['oldSearch']) && isset($_SESSION[COOKIENAME.'search'][$_GET['oldSearch']]['operators'][$field])) + $operator = $_SESSION[COOKIENAME.'search'][$_GET['oldSearch']]['operators'][$field]; + elseif($typeAffinity=="TEXT" || $typeAffinity=="NONE") + $operator = 'LIKE'; + else + $operator = '='; + + echo "
"; + echo ""; + echo "
"; + echo ""; + + break; + } + elseif(isset($_SESSION[COOKIENAME.'search'][$_GET['search']])) + { + $params->search = $_GET['search']; + $search = $_SESSION[COOKIENAME.'search'][$_GET['search']]; + // NOTICE: we do not break here!! we just do the same now like row_view-action does + } + + //- Row actions + + //- View row (=row_view) + case "row_view": + if(!isset($_GET['startRow'])) + $_GET['startRow'] = 0; + + if(isset($_SESSION[COOKIENAME.'currentTable']) && $_SESSION[COOKIENAME.'currentTable']!=$target_table) + { + unset($_SESSION[COOKIENAME.'sortRows']); + unset($_SESSION[COOKIENAME.'orderRows']); + } + if(isset($_GET['viewtype'])) + { + $_SESSION[COOKIENAME.'viewtype'] = $_GET['viewtype']; + } + + //- Query execution + if(!isset($_GET['sort'])) + $_GET['sort'] = NULL; + if(!isset($_GET['order'])) + $_GET['order'] = NULL; + + $numRows = $params->numRows; + $startRow = $_GET['startRow']; + if(isset($_GET['sort'])) + { + $_SESSION[COOKIENAME.'sortRows'] = $_GET['sort']; + $_SESSION[COOKIENAME.'currentTable'] = $target_table; + } + if(isset($_GET['order'])) + { + $_SESSION[COOKIENAME.'orderRows'] = $_GET['order']; + $_SESSION[COOKIENAME.'currentTable'] = $target_table; + } + $query = "SELECT * "; + // select the primary key column(s) last (ROWID if there is no PK). + // this will be used to identify rows, e.g. when editing/deleting rows + $primary_key = $db->getPrimaryKey($target_table); + foreach($primary_key as $pk) + { + $query.= ', '.$db->quote_id($pk); + $query.= ', typeof('.$db->quote_id($pk).')'; + } + $query .= " FROM ".$db->quote_id($target_table); + $queryDisp = "SELECT * FROM ".$db->quote_id($target_table); + $queryCount = "SELECT COUNT(*) AS count FROM ".$db->quote_id($target_table); + $queryAdd = ""; + if(isset($search) && isset($search['where'])) + { + $queryAdd = $search['where']; + $queryCount .= $search['where']; + } + if(isset($_SESSION[COOKIENAME.'sortRows'])) + $queryAdd .= " ORDER BY ".$db->quote_id($_SESSION[COOKIENAME.'sortRows']); + if(isset($_SESSION[COOKIENAME.'orderRows'])) + $queryAdd .= " ".$_SESSION[COOKIENAME.'orderRows']; + $queryAdd .= " LIMIT ".$startRow.", ".$numRows; + $query .= $queryAdd; + $queryDisp .= $queryAdd; + + $resultRows = $db->select($queryCount); + $totalRows = $resultRows['count']; + $shownRows = min($resultRows['count']-$startRow, $numRows); + + //- HTML: pagination buttons + $lastPage = intval($totalRows / $params->numRows); + $remainder = intval($totalRows % $params->numRows); + if($remainder==0) + $remainder = $params->numRows; + + echo "
"; + //previous button + if($_GET['startRow']>0) + { + echo "
"; + echo $params->getForm(array('action'=>$_GET['action']),'get'); + echo ""; + echo " "; + echo ""; + echo "
"; + echo "
"; + echo $params->getForm(array('action'=>$_GET['action']),'get'); + echo "numRows))."'/>"; + echo " "; + echo ""; + echo "
"; + } + + //show certain number buttons + echo "
"; + echo $params->getForm(array('action'=>$_GET['action'], 'numRows'=>null),'get'); + echo " "; + echo " "; + echo $lang['rows_records']; + + if(intval($_GET['startRow']+$params->numRows) < $totalRows) + echo "numRows)."'/>"; + else + echo " "; + echo $lang['as_a']; + echo " "; + echo ""; + echo "
"; + + //next button + if(intval($_GET['startRow']+$params->numRows)<$totalRows) + { + echo "
"; + echo $params->getForm(array('action'=>$_GET['action']),'get'); + echo "numRows)."'/>"; + echo " "; + echo ""; + echo "
"; + echo "
"; + echo $params->getForm(array('action'=>$_GET['action']),'get'); + echo ""; + echo " "; + echo ""; + echo "
"; + } + echo "
"; + echo "
"; + + + //- Show results + if($shownRows>0) + { + $queryTimer = new MicroTimer(); + $table_result = $db->query($query); + $queryTimer->stop(); + + + echo "
"; + echo "".$lang['showing_rows']." ".$startRow." - ".($startRow + $shownRows-1).", ".$lang['total'].": ".$totalRows." "; + printf($lang['query_time'], $queryTimer); + echo "
"; + echo "".htmlencode($queryDisp).""; + echo "

"; + + if($target_table_type == 'view') + { + echo sprintf($lang['readonly_tbl'], htmlencode($target_table))." https://en.wikipedia.org/wiki/View_(SQL)"; + echo "

"; + } + + $tableInfo = $db->getTableInfo($target_table); + $pkFirstCol = sizeof($tableInfo)+1; + //- Table view + if(!isset($_SESSION[COOKIENAME.'viewtype']) || $_SESSION[COOKIENAME.'viewtype']=="table") + { + echo $params->getForm(array('action'=>'row_editordelete'), 'post', false, 'checkForm'); + echo ""; + echo ""; + echo ""; + + for($i=0; $i"; + if(isset($_SESSION[COOKIENAME.'sortRows'])) + $orderTag = ($_SESSION[COOKIENAME.'sortRows']==$tableInfo[$i]['name'] && $_SESSION[COOKIENAME.'orderRows']=="ASC") ? "DESC" : "ASC"; + else + $orderTag = "ASC"; + echo $params->getLink(array('action'=>$_GET['action'], 'sort'=>$tableInfo[$i]['name'], 'order'=>$orderTag ), htmlencode($tableInfo[$i]['name'])); + if(isset($_SESSION[COOKIENAME.'sortRows']) && $_SESSION[COOKIENAME.'sortRows']==$tableInfo[$i]['name']) + echo (($_SESSION[COOKIENAME.'orderRows']=="ASC") ? " " : " "); + echo ""; + } + echo ""; + + for($i=0; $row = $db->fetch($table_result, 'num'); $i++) + { + // -g-> $pk will always be the last columns in each row of the array because we are doing "SELECT *, PK_1, typeof(PK_1), PK2, typeof(PK_2), ... FROM ..." + $pk_arr = array(); + for($col = $pkFirstCol; array_key_exists($col, $row); $col=$col+2) + { + // in $col we have the type and in $col-1 the value + if($row[$col]=='integer' || $row[$col]=='real') + // json encode as int or float, not string + $pk_arr[] = $row[$col-1]+0; + else + // encode as json string + $pk_arr[] = $row[$col-1]; + } + $pk = json_encode($pk_arr); + $tdWithClass = ""; + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + { + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + // -g-> Here, we need to put the PK in as the link for both the edit and delete. + echo $params->getLink(array('action'=>'row_editordelete', 'pk'=>$pk, 'type'=>'edit'),"".$lang['edit']."",'edit', $lang['edit']); + echo ""; + echo $tdWithClass; + echo $params->getLink(array('action'=>'row_editordelete', 'pk'=>$pk, 'type'=>'delete'),"".$lang['del']."",'delete', $lang['del']); + echo ""; + } else { + echo ""; + } + for($j=0; $jNULL"; + elseif(preg_match('/^BLOB/i', $tableInfo[$j]['type'])) + { + echo "
"; + echo $params->getLink(array('action'=>'row_get_blob', 'confirm'=>1, 'pk'=>$pk, 'column'=>$tableInfo[$j]['name'], 'download_blob'=>1),$lang["download"]).' | '; + echo $params->getLink(array('action'=>'row_get_blob', 'confirm'=>1, 'pk'=>$pk, 'column'=>$tableInfo[$j]['name'], 'download_blob'=>0),$lang["open_in_browser"],'','','_blank'); + echo "
"; + echo 'Size: '.number_format(strlen($row[$j])).' Bytes'; + echo "
"; + } + elseif(isset($search)) + echo markSearchWords(subString($row[$j]),$tableInfo[$j]['name'], $search); + else + echo htmlencode(subString($row[$j])); + echo ""; + } + echo "
"; + } + echo "
"; + echo "$_GET['action'], 'fulltexts'=>($params->fulltexts?0:1) ))."' title='".$lang[($params->fulltexts?'no_full_texts':'full_texts')]."'>"; + echo "&".($params->fulltexts?'r':'l')."arr; T &".($params->fulltexts?'l':'r')."arr;"; + echo "
"; + $tdWithClassLeft = ""; + echo "
"; + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + { + echo "".$lang['chk_all']." / ".$lang['unchk_all']." ".$lang['with_sel'].": "; + echo " "; + echo ""; + } + echo ""; + } + else + //- Chart view + { + if(!isset($_SESSION[COOKIENAME.$target_table.'chartlabels'])) + { + // No label-column set. Try to pick a text-column as label-column. + for($i=0; $i + + +
+ Chart Settings"; + echo $params->getForm(array('action'=>$_GET['action'])); + echo $lang['chart_type'].": "; + echo "

"; + echo $lang['lbl'].": "; + echo "

"; + echo $lang['val'].": "; + echo "

"; + echo ""; + echo ""; + echo ""; + echo "
"; + //end chart view + } + } + else //no rows - do nothing + { + echo "
"; + if(isset($search) || $totalRows>0) + echo $lang['no_rows']."

"; + elseif($target_table_type == 'table') + echo $lang['empty_tbl']." ".$params->getLink(array('action'=>'row_create'), $lang['click']) ." ".$lang['insert_rows'].'

'; + echo "".htmlencode($queryDisp).""; + echo "

"; + } + + if(isset($search)) + echo "

".$params->getLink(array('action'=>'table_search','search'=>null,'oldSearch' => (isset($_GET['search'])?$_GET['search']:null)), $lang['srch_again']); + + break; + + //- Create new row (=row_create) + case "row_create": + echo $params->getForm(array('action'=>'row_create'), 'get'); + echo $lang['restart_insert']; + echo " "; + echo $lang['rows']; + echo " "; + echo ""; + echo "
"; + echo $params->getForm(array('action'=>'row_create','confirm'=>'1'), 'post', true); + $tableInfo = $db->getTableInfo($target_table); + if(isset($_GET['newRows'])) + $num = $_GET['newRows']; + else + $num = 1; + echo ""; + for($j=0; $j<$num; $j++) + { + if($j>0) + echo "
"; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + for($i=0; $i"; + echo ""; + echo $tdWithClassLeft; + echo htmlencode($field); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($type); + echo ""; + echo $tdWithClassLeft; + echo ""; + echo ""; + echo $tdWithClassLeft; + if($tableInfo[$i]['notnull']==0) + { + if($value===NULL) + echo ""; + else + echo ""; + } + echo ""; + echo $tdWithClassLeft; + + if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC") + echo ""; + elseif(preg_match('/^BLOB/', $type)) + echo ""; + else + echo ""; + echo ""; + echo ""; + } + echo ""; + echo ""; + echo ""; + echo "
".$lang['fld']."".$lang['type']."".$lang['func']."Null".$lang['val']."
"; + echo ""; + echo "

"; + } + echo ""; + break; + + //- Edit or delete row (=row_editordelete) + case "row_editordelete": + if(isset($_POST['check'])) + $pks = $_POST['check']; + else if(isset($_GET['pk'])) + $pks = array($_GET['pk']); + else $pks[0] = ""; + $str = implode(', ', $pks); + if($str=="") //nothing was selected so show an error + { + echo "
"; + echo $lang['err'].": ".$lang['no_sel']; + echo "
"; + echo "

".$params->getLink(array('action'=>'row_view'),$lang['return']); + } + else + { + if((isset($_POST['type']) && $_POST['type']=="edit") || (isset($_GET['type']) && $_GET['type']=="edit")) //edit + { + echo $params->getForm(array('action'=>'row_edit', 'confirm'=>'1', 'pk'=>json_encode($pks)),'post',true); + $tableInfo = $db->getTableInfo($target_table); + $primary_key = $db->getPrimaryKey($target_table); + + for($j=0; $jquote_id($target_table)." WHERE " . $db->wherePK($target_table, json_decode($pks[$j])); + $result1 = $db->select($query, 'num'); + + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + for($i=0; $i"; + echo ""; + echo $tdWithClassLeft; + echo htmlencode($field); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($type); + echo ""; + echo $tdWithClassLeft; + echo ""; + echo ""; + echo $tdWithClassLeft; + if($tableInfo[$i]['notnull']==0) + { + if($value===NULL) + echo ""; + else + echo ""; + } + echo ""; + echo $tdWithClassLeft; + if($typeAffinity=="INTEGER" || $typeAffinity=="REAL" || $typeAffinity=="NUMERIC") + echo ""; + elseif(preg_match('/^BLOB/', $type)) + { + if($value!==NULL) + { + echo ""; + echo $params->getLink(array('action'=>'row_get_blob', 'confirm'=>1, 'pk'=>$pks[$j], 'column'=>$field, 'download_blob'=>1),$lang["download"]).' | '; + echo $params->getLink(array('action'=>'row_get_blob', 'confirm'=>1, 'pk'=>$pks[$j], 'column'=>$field, 'download_blob'=>0),$lang["open_in_browser"],'','','_blank').'
'; + echo ""; + } + echo ""; + } + else + echo ""; + echo ""; + echo ""; + } + echo ""; + echo ""; + echo ""; + echo "
".$lang['fld']."".$lang['type']."".$lang['func']."Null".$lang['val']."
"; + // Note: the 'Save changes' button must be first in the code so it is the one used when submitting the form with the Enter key (issue #215) + echo " "; + echo " "; + echo $params->getLink(array('action'=>'row_view'), $lang['cancel']); + echo "
"; + echo "
"; + } + echo ""; + } + else //delete + { + echo $params->getForm(array('action'=>'row_delete', 'confirm'=>'1', 'pk'=>json_encode($pks))); + echo "
"; + printf($lang['ques_del_rows'], htmlencode($str), htmlencode($target_table)); + echo "

"; + echo " "; + echo $params->getLink(array('action'=>'row_view'), $lang['cancel']); + echo "
"; + } + } + break; + + //- Column actions + + //- View table structure (=column_view) + case "column_view": + $tableInfo = $db->getTableInfo($target_table); + + echo $params->getForm(array('action'=>'column_confirm'), 'get', false, 'checkForm'); + echo ""; + echo ""; + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + $noPrimaryKey = true; + + for($i=0; $i"; + $tdWithClassLeft = ""; + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + { + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo $params->getLink(array('action'=>'column_edit', 'pk'=>$fieldVal),"".$lang['edit']."",'edit', $lang['edit']); + echo ""; + echo $tdWithClass; + echo $params->getLink(array('action'=>'column_confirm', 'action2'=>'column_delete', 'pk'=>$fieldVal),"".$lang['del']."",'delete', $lang['del']); + echo ""; + } + echo $tdWithClass; + echo htmlencode($colVal); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($fieldVal); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($typeVal); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($notnullVal); + echo ""; + echo $tdWithClassLeft; + if($defaultVal===NULL) + echo "".$lang['none'].""; + elseif($defaultVal==="NULL") + echo "NULL"; + else + echo htmlencode($defaultVal); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($primarykeyVal); + echo ""; + echo ""; + } + + echo "
".$lang['col']." #".$lang['fld']."".$lang['type']."".$lang['not_null']."".$lang['def_val']."".$lang['prim_key']."
"; + echo "
"; + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + { + echo "".$lang['chk_all']." / ".$lang['unchk_all']." ".$lang['with_sel'].": "; + echo " "; + echo ""; + } + echo ""; + if($target_table_type == 'table' && $db->isWritable() && $db->isDirWritable()) + { + echo "
"; + echo $params->getForm(array('action'=>'column_create'), 'get'); + echo $lang['add']." ".$lang['tbl_end']." "; + echo ""; + } + + $query = "SELECT sql FROM sqlite_master WHERE name=".$db->quote($target_table); + $master = $db->selectArray($query); + + echo "
"; + echo "
"; + echo "
"; + echo "".$lang['query_used_'.$target_table_type]."
"; + echo "".htmlencode($master[0]['sql']).""; + echo "
"; + echo "
"; + if($target_table_type != 'view') + { + echo "


"; + $query = "PRAGMA index_list(".$db->quote_id($target_table).")"; + $result = $db->selectArray($query); + if(sizeof($result)>0) + { + echo "

".$lang['indexes'].":

"; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + for($i=0; $iquote_id($result[$i]['name']).")"; + $info = $db->selectArray($query); + $span = sizeof($info); + + $tdWithClass = ""; + echo $tdWithClassSpan; + echo $params->getLink(array('action'=>'index_delete', 'pk'=>$result[$i]['name']), "".$lang['del']."", 'delete', $lang['del']); + echo ""; + echo $tdWithClassLeftSpan; + echo $result[$i]['name']; + echo ""; + echo $tdWithClassLeftSpan; + echo $unique; + echo ""; + for($j=0; $j<$span; $j++) + { + if($j!=0) + echo ""; + echo $tdWithClassLeft; + echo htmlencode($info[$j]['seqno']); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($info[$j]['cid']); + echo ""; + echo $tdWithClassLeft; + echo htmlencode($info[$j]['name']); + echo ""; + echo ""; + } + } + echo "
"; + echo "".$lang['name']."".$lang['unique']."".$lang['seq_no']."".$lang['col']." #".$lang['fld']."
"; + $tdWithClassLeft = ""; + $tdWithClassSpan = ""; + $tdWithClassLeftSpan = ""; + echo "


"; + } + + $query = "SELECT * FROM sqlite_master WHERE type='trigger' AND tbl_name=".$db->quote($target_table)." ORDER BY name"; + $result = $db->selectArray($query); + //print_r($result); + if(sizeof($result)>0) + { + echo "

".$lang['triggers'].":

"; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + for($i=0; $i"; + echo ""; + echo $tdWithClass; + echo $params->getLink(array('action'=>'trigger_delete', 'pk'=>$result[$i]['name']), "".$lang['del']."", 'delete', $lang['del']); + echo ""; + echo $tdWithClass; + echo htmlencode($result[$i]['name']); + echo ""; + echo $tdWithClass; + echo htmlencode($result[$i]['sql']); + echo ""; + } + echo "
"; + echo "".$lang['name']."".$lang['sql']."


"; + } + + if($db->isWritable() && $db->isDirWritable()) + { + echo $params->getForm(array('action'=>'index_create'),'get'); + echo "
"; + echo $lang['create_index2']." ".$lang['cols']." "; + echo "
"; + echo ""; + + echo $params->getForm(array('action'=>'trigger_create'),'get'); + echo "
"; + echo $lang['create_trigger2']." "; + echo "
"; + echo ""; + } + } + break; + + //- Create column (=column_create) + case "column_create": + echo "

".sprintf($lang['new_fld'],htmlencode($_GET['table']))."

"; + if($_GET['tablefields']=="" || intval($_GET['tablefields'])<=0) + echo $lang['specify_fields']; + else if($_GET['table']=="") + echo $lang['specify_tbl']; + else + { + $num = intval($_GET['tablefields']); + $name = $_GET['table']; + echo $params->getForm(array('action'=>'column_create', 'confirm'=>'1')); + echo ""; + echo ""; + echo ""; + $headings = array($lang["fld"], $lang["type"], $lang["prim_key"]); + if($db->getType() != "SQLiteDatabase") $headings[] = $lang["autoincrement"]; + $headings[] = $lang["not_null"]; + $headings[] = $lang["def_val"]; + + for($k=0; $k" . $headings[$k] . ""; + echo ""; + + for($i=0; $i<$num; $i++) + { + $tdWithClass = ""; + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + if($db->getType() != "SQLiteDatabase") + { + echo $tdWithClass; + echo ""; + echo ""; + } + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + echo ""; + echo ""; + } + echo ""; + echo ""; + echo ""; + echo "
"; + echo "
"; + echo " "; + echo $params->getLink(array('action'=>'column_view'), $lang['cancel']); + echo "
"; + echo ""; + } + break; + + //- Delete column (=column_confirm) + case "column_confirm": + if(isset($_GET['check'])) + $pks = $_GET['check']; + elseif(isset($_GET['pk'])) + $pks = array($_GET['pk']); + else $pks = array(); + + if(sizeof($pks)==0) //nothing was selected so show an error + { + echo "
"; + echo $lang['err'].": ".$lang['no_sel']; + echo "
"; + echo "

"; + echo $params->getLink(array('action'=>'column_view'), $lang['return']); + } + else + { + $str = $pks[0]; + $pkVal = $pks[0]; + for($i=1; $igetForm(array('action'=>$_GET['action2'], 'confirm'=>'1', 'pk'=>$pkVal)); + echo "
"; + printf($lang['ques_'.$_GET['action2']], htmlencode($str), htmlencode($target_table)); + echo "

"; + echo " "; + echo $params->getLink(array('action'=>'column_view'), $lang['cancel']); + echo "
"; + } + break; + + //- Edit column (=column_edit) + case "column_edit": + echo "

".sprintf($lang['edit_col'], htmlencode($_GET['pk']))." ".$lang['on_tbl']." '".htmlencode($target_table)."'

"; + echo $lang['sqlite_limit']."

"; + if(!isset($_GET['pk'])) + echo $lang['specify_col']; + else if (!$target_table) + echo $lang['specify_tbl']; + else + { + $tableInfo = $db->getTableInfo($target_table); + + for($i=0; $i".$lang['err'].": ".sprintf($lang['col_inexistent'], htmlencode($_GET['pk'])).""; + } + else + { + $name = $target_table; + echo $params->getForm(array('action'=>'column_edit', 'confirm'=>'1')); + echo ""; + echo ""; + echo ""; + //$headings = array("Field", "Type", "Primary Key", "Autoincrement", "Not NULL", "Default Value"); + $headings = array($lang["fld"], $lang["type"]); + for($k=0; $k".$headings[$k].""; + echo ""; + + $i = 0; + $tdWithClass = ""; + echo $tdWithClass; + echo ""; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + /* + echo $tdWithClass; + if($primarykeyVal) + echo " Yes"; + else + echo " Yes"; + echo ""; + echo $tdWithClass; + if(1==2) + echo " Yes"; + else + echo " Yes"; + echo ""; + echo $tdWithClass; + if($notnullVal) + echo " Yes"; + else + echo " Yes"; + echo ""; + echo $tdWithClass; + echo ""; + echo ""; + */ + echo ""; + + echo ""; + echo ""; + echo ""; + echo "
"; + echo "
"; + echo " "; + echo $params->getLink(array('action'=>'column_view'), $lang['cancel']); + echo "
"; + echo ""; + } + } + break; + + //- Delete index (=index_delete) + case "index_delete": + echo $params->getForm(array('action'=>'index_delete', 'pk'=>$_GET['pk'], 'confirm'=>'1')); + echo "
"; + echo sprintf($lang['ques_del_index'], htmlencode($_GET['pk']))."

"; + echo " "; + echo $params->getLink(array('action'=>'column_view'), $lang['cancel']); + echo "
"; + echo ""; + break; + + //- Delete trigger (=trigger_delete) + case "trigger_delete": + echo $params->getForm(array('action'=>'trigger_delete', 'pk'=>$_GET['pk'], 'confirm'=>'1')); + echo "
"; + echo sprintf($lang['ques_del_trigger'], htmlencode($_GET['pk']))."

"; + echo " "; + echo $params->getLink(array('action'=>'column_view'), $lang['cancel']); + echo "
"; + echo ""; + break; + + //- Create trigger (=trigger_create) + case "trigger_create": + echo "

".$lang['create_trigger']." '".htmlencode($_GET['table'])."'

"; + if($_GET['table']=="") + echo $lang['specify_tbl']; + else + { + echo $params->getForm(array('action'=>'trigger_create', 'confirm'=>'1')); + echo $lang['trigger_name'].":

"; + echo "
".$lang['db_event'].""; + echo $lang['before']."/".$lang['after'].": "; + echo ""; + echo "

"; + echo $lang['event'].": "; + echo ""; + echo "


"; + echo "
".$lang['trigger_act'].""; + echo "

"; + echo $lang['when_exp'].":
"; + echo ""; + echo "

"; + echo $lang['trigger_step'].":
"; + echo ""; + echo "


"; + echo " "; + echo $params->getLink(array('action'=>'column_view'), $lang['cancel']); + echo ""; + } + break; + + //- Create index (=index_create) + case "index_create": + echo "

".$lang['create_index']." '".htmlencode($_GET['table'])."'

"; + if($_GET['numcolumns']=="" || intval($_GET['numcolumns'])<=0) + echo $lang['specify_fields']; + else if($_GET['table']=="") + echo $lang['specify_tbl']; + else + { + echo $params->getForm(array('action'=>'index_create', 'confirm'=>'1')); + $num = intval($_GET['numcolumns']); + $tableInfo = $db->getTableInfo($_GET['table']); + echo "
".$lang['define_index'].""; + echo "
"; + echo ""; + echo "
"; + if(version_compare($db->getSQLiteVersion(),'3.8.0')>=0) + echo " ".helpLink($lang['help10']); + echo "
"; + echo "
"; + echo "
".$lang['define_in_col'].""; + for($i=0; $i<$num; $i++) + { + echo " "; + echo "
"; + } + echo "
"; + echo "

"; + echo ""; + echo " "; + echo $params->getLink(array('action'=>'column_view'), $lang['cancel']); + echo ""; + } + break; + } + echo ""; +} + +//- HMTL: views for databases +if(!$target_table && !isset($_GET['confirm']) && (!isset($_GET['action']) || (isset($_GET['action']) && $_GET['action']!="table_create"))) //the absence of these fields means we are viewing the database homepage +{ + //- Switch on $view (actually a series of if-else) + + if($view=="structure") + { + //- Database structure, shows all the tables (=structure) + + if($db->isWritable() && !$db->isDirWritable()) + { + echo "
"; + echo $lang['attention'].': '.$lang['directory_not_writable']; + echo "

"; + } + elseif(!$db->isWritable()) + { + echo "
"; + echo $lang['attention'].': '.$lang['database_not_writable']; + echo "

"; + } + + if ($auth->isPasswordDefault()) + { + echo "
"; + echo sprintf($lang['warn_passwd'],(is_readable('phpliteadmin.config.php')?'phpliteadmin.config.php':basename(__FILE__)))."
".$lang['warn0']; + echo "
"; + } + + echo "".$lang['db_name'].": ".htmlencode($db->getName())."
"; + echo "".$lang['db_path'].": ".htmlencode($db->getPath())."
"; + echo "".$lang['db_size'].": ".number_format($db->getSize())." KiB
"; + echo "".$lang['db_mod'].": ".$db->getDate()."
"; + echo "".$lang['sqlite_v'].": ".$db->getSQLiteVersion()."
"; + echo "".$lang['sqlite_ext']." ".helpLink($lang['help1']).": ".$db->getType()."
"; + echo "".$lang['php_v'].": ".phpversion()."
"; + echo "".PROJECT." ".$lang["ver"].": ".VERSION; + echo "

"; + echo ""; + + if(isset($_GET['sort']) && ($_GET['sort']=='type' || $_GET['sort']=='name')) + $_SESSION[COOKIENAME.'sortTables'] = $_GET['sort']; + if(isset($_GET['order']) && ($_GET['order']=='ASC' || $_GET['order']=='DESC')) + $_SESSION[COOKIENAME.'orderTables'] = $_GET['order']; + + if(!isset($_SESSION[COOKIENAME.'sortTables'])) + $_SESSION[COOKIENAME.'sortTables'] = 'name'; + + if(!isset($_SESSION[COOKIENAME.'orderTables'])) + $_SESSION[COOKIENAME.'orderTables'] = 'ASC'; + + $tables = $db->getTables(true, false, $_SESSION[COOKIENAME.'sortTables'], $_SESSION[COOKIENAME.'orderTables']); + + if(sizeof($tables)==0) + echo $lang['no_tbl']."

"; + else + { + echo ""; + echo ""; + + echo ""; + + echo ""; + + echo ""; + echo ""; + echo ""; + + $totalRecords = 0; + $skippedTables = false; + foreach($tables as $tableName => $tableType) + { + $records = $db->numRows($tableName, (!isset($_GET['forceCount']))); + if($records == '?') + { + $skippedTables = true; + $records = $params->getLink(array('forceCount'=>'1'), '?'); + } + else + $totalRecords += $records; + $tdWithClass = ""; + echo $tdWithClassLeft; + echo ($tableType=="table"? $lang['tbl'] : $lang['view']); + echo ""; + echo $tdWithClassLeft; + echo $params->getLink(array('table'=>$tableName, 'action'=>'row_view'), htmlencode($tableName)); + echo ""; + echo $tdWithClass; + echo $params->getLink(array('table'=>$tableName, 'action'=>'row_view'), $lang['browse']); + echo ""; + echo $tdWithClass; + echo $params->getLink(array('table'=>$tableName, 'action'=>'column_view'), $lang['struct']); + echo ""; + echo $tdWithClass; + echo $params->getLink(array('table'=>$tableName, 'action'=>'table_sql'), $lang['sql']); + echo ""; + echo $tdWithClass; + echo $params->getLink(array('table'=>$tableName, 'action'=>'table_search'), $lang['srch']); + echo ""; + echo $tdWithClass; + if($tableType=="table" && $db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('table'=>$tableName, 'action'=>'row_create'), $lang['insert']); + else + echo $lang['insert']; + echo ""; + echo $tdWithClass; + echo $params->getLink(array('table'=>$tableName, 'action'=>'table_export'), $lang['export']); + echo ""; + echo $tdWithClass; + if($tableType=="table" && $db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('table'=>$tableName, 'action'=>'table_import'), $lang['import']); + else + echo $lang['import']; + echo ""; + echo $tdWithClass; + if($db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('table'=>$tableName, 'action'=>'table_rename'), $lang['rename']); + else + echo $lang['rename']; + echo ""; + echo $tdWithClass; + if($tableType=="table" && $db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('table'=>$tableName, 'action'=>'table_empty'), $lang['empty'], 'empty'); + else + echo $lang['empty']; + echo ""; + echo $tdWithClass; + if($db->isWritable() && $db->isDirWritable()) + echo $params->getLink(array('table'=>$tableName, 'action'=>'table_drop'), $lang['drop'], 'drop'); + else + echo $lang['drop']; + echo ""; + echo $tdWithClass; + echo $records; + echo ""; + echo ""; + } + echo ""; + echo ""; + echo ""; + echo ""; + echo "
"; + if(isset($_SESSION[COOKIENAME.'sortTables'])) + $orderTag = ($_SESSION[COOKIENAME.'sortTables']=="type" && $_SESSION[COOKIENAME.'orderTables']=="ASC") ? "DESC" : "ASC"; + else + $orderTag = "ASC"; + echo $params->getLink(array('sort'=>'type', 'order'=>$orderTag), $lang['type']); + echo helpLink($lang['help3']); + if(isset($_SESSION[COOKIENAME.'sortTables']) && $_SESSION[COOKIENAME.'sortTables']=="type") + echo (($_SESSION[COOKIENAME.'orderTables']=="ASC") ? " " : " "); + echo ""; + if(isset($_SESSION[COOKIENAME.'sortTables'])) + $orderTag = ($_SESSION[COOKIENAME.'sortTables']=="name" && $_SESSION[COOKIENAME.'orderTables']=="ASC") ? "DESC" : "ASC"; + else + $orderTag = "ASC"; + echo $params->getLink(array('sort'=>'name', 'order'=>$orderTag), $lang['name']); + if(isset($_SESSION[COOKIENAME.'sortTables']) && $_SESSION[COOKIENAME.'sortTables']=="name") + echo (($_SESSION[COOKIENAME.'orderTables']=="ASC") ? " " : " "); + echo "".$lang['act']."".$lang['rec']."
"; + $tdWithClassLeft = ""; + + echo "
".sizeof($tables)." ".$lang['total']."".$totalRecords.($skippedTables?" ".$params->getLink(array('forceCount'=>'1'),'+ ?'):"")."
"; + echo "
"; + if($skippedTables) + echo "
".sprintf($lang["counting_skipped"],"'1'))."'>","")."
"; + } + if($db->isWritable() && $db->isDirWritable()) + { + echo "
"; + echo "".$lang['create_tbl_db']." '".htmlencode($db->getName())."'"; + echo $params->getForm(array('action'=>'table_create'), 'get'); + echo $lang['name'].": "; + echo $lang['fld_num'].": "; + echo ""; + echo ""; + echo "
"; + echo "
"; + echo "
"; + echo "".$lang['create_view']." '".htmlencode($db->getName())."'"; + echo $params->getForm(array('action'=>'view_create', 'confirm'=>'1')); + echo $lang['name'].": "; + echo $lang['sel_state']." ".helpLink($lang['help4']).": "; + echo ""; + echo ""; + echo "
"; + } + } + else if($view=="sql") + { + //- Database SQL editor (=sql) + if(isset($_POST['query']) && $_POST['query']!="") + { + $delimiter = $_POST['delimiter']; + $queryStr = $_POST['queryval']; + //save the queries in history if necessary + if($maxSavedQueries!=0 && $maxSavedQueries!=false) + { + if(!isset($_SESSION[COOKIENAME.'query_history'])) + $_SESSION[COOKIENAME.'query_history'] = array(); + $_SESSION[COOKIENAME.'query_history'][md5(strtolower($queryStr))] = $queryStr; + if(sizeof($_SESSION[COOKIENAME.'query_history']) > $maxSavedQueries) + array_shift($_SESSION[COOKIENAME.'query_history']); + } + $query = explode_sql($delimiter, $queryStr); //explode the query string into individual queries based on the delimiter + + for($i=0; $iquery($query[$i]); + + echo "
"; + echo "".htmlencode($query[$i]).""; + if($table_result === NULL || $table_result === false) + { + echo "
".$lang['err'].": ".htmlencode($db->getError())."
"; + } + echo "
"; + if($row = $db->fetch($table_result, 'num')) + { + for($j=0; $jgetColumnName($table_result,$j); + echo ""; + echo ""; + for($j=0; $j"; + echo htmlencode($headers[$j]); + echo ""; + } + echo ""; + $rowCount = 0; + for(; $rowCount==0 || $row = $db->fetch($table_result, 'num'); $rowCount++) + { + $tdWithClass = ""; + for($z=0; $zNULL"; + else + echo htmlencode(subString($row[$z])); + echo ""; + } + echo ""; + } + $queryTimer->stop(); + echo "
"; + echo "


"; + + + if($table_result !== NULL && $table_result !== false) + { + echo "
"; + if($rowCount>0 || $db->getAffectedRows()==0) + { + printf($lang['show_rows'], $rowCount); + } + if($db->getAffectedRows()>0 || $rowCount==0) + { + echo $db->getAffectedRows()." ".$lang['rows_aff']." "; + } + printf($lang['query_time'], $queryTimer); + echo "
"; + } + + + } + } + } + } + else + { + $delimiter = ";"; + $queryStr = ""; + } + + echo "
"; + echo "".sprintf($lang['run_sql'],htmlencode($db->getName())).""; + echo $params->getForm(array('view'=>'sql')); + if(isset($_SESSION[COOKIENAME.'query_history']) && sizeof($_SESSION[COOKIENAME.'query_history'])>0) + { + echo "".$lang['recent_queries']."
    "; + foreach($_SESSION[COOKIENAME.'query_history'] as $key => $value) + { + echo "
  • ".htmlencode($value)."
  • "; + } + echo "


"; + } + echo ""; + echo ""; + echo $lang['delimit']." "; + echo ""; + echo ""; + echo "
"; + } + else if($view=="vacuum") + { + //- Vacuum database confirmation (=vacuum) + if(isset($_POST['vacuum'])) + { + $query = "VACUUM"; + $db->query($query); + echo "
"; + printf($lang['db_vac'], htmlencode($db->getName())); + echo "

"; + } + echo $params->getForm(array('view'=>'vacuum')); + printf($lang['vac_desc'],htmlencode($db->getName())); + echo "

"; + echo ""; + echo ""; + } + else if($view=="export") + { + //- Export view (=export) + echo $params->getForm(array('view'=>'export')); + echo "
".$lang['export'].""; + echo ""; + echo "

"; + echo ""; + echo "
"; + echo "
"; + + echo "
".$lang['options'].""; + echo " ".helpLink($lang['help5'])."
"; + echo " ".helpLink($lang['help6'])."
"; + echo " ".helpLink($lang['help7'])."
"; + echo " ".helpLink($lang['help8'])."
"; + echo " ".helpLink($lang['help9'])."
"; + echo "
"; + + echo ""; + + echo "
"; + echo "

"; + echo "
".$lang['save_as'].""; + $file = pathinfo($db->getPath()); + $name = $file['filename']; + echo " "; + echo "
"; + echo ""; + echo "
".sprintf($lang['backup_hint'], + $params->getLink(array('download'=>$currentDB['path'], 'token'=>$_SESSION[COOKIENAME.'token']), $lang["backup_hint_linktext"], '', $lang['backup']) + )."
"; + } + else if($view=="import") + { + //- Import view (=import) + if(isset($_POST['import'])) + { + echo "
"; + if($importSuccess===true) + echo $lang['import_suc']; + else + echo $importSuccess; + echo "

"; + } + + echo $params->getForm(array('view'=>'import'), 'post', true); + echo "
".$lang['import'].""; + echo ""; + echo "
"; + echo "
"; + + echo "
".$lang['options'].""; + echo $lang['no_opt']; + echo "
"; + + echo ""; + + echo "
"; + echo "

"; + + echo "
".$lang['import_f'].""; + echo "".$lang['max_file_size'].": ".number_format(fileUploadMaxSize()/1024/1024)." MiB ".helpLink($lang['help11'])."
"; + echo ""; + echo ""; + echo "
"; + } + else if($view=="rename") + { + //- Rename database confirmation (=rename) + echo $params->getForm(array('view'=>'rename', 'database_rename'=>'1')); + echo ""; + echo $lang['db_rename']." '".htmlencode($db->getPath())."' ".$lang['to']." "; + echo ""; + } + else if($view=="delete") + { + //- Delete database confirmation (=delete) + echo $params->getForm(array('database_delete'=>'1')); + echo "
"; + echo sprintf($lang['ques_del_db'],htmlencode($db->getPath()))."

"; + echo ""; + echo " "; + echo $params->getLink(array(), $lang['cancel']); + echo "
"; + echo ""; + } + + echo ""; +} +echo ""; + +//- HTML: page footer +echo "
"; +echo "".$lang['powered']." ".PROJECT." | "; +echo $lang['free_software']." ".$lang['please_donate']." | "; +printf($lang['page_gen'], $pageTimer); +echo ""; +echo "
"; +$db->close(); //close the database +echo ""; +echo ""; + +//- End of main code + +// Authorization class +// Maintains user's logged-in state and security of application +// + +class Authorization +{ + private $authorized; + private $login_failed; + private $system_password_encrypted; + + public function __construct() + { + // first, make sure a CSRF token is generated + $this->generateToken(); + // second, check for possible CSRF attacks. to protect logins, this is done before checking login + $this->checkToken(); + + // the salt and password encrypting is probably unnecessary protection but is done just + // for the sake of being very secure + if(!isset($_SESSION[COOKIENAME.'_salt']) && !isset($_COOKIE[COOKIENAME.'_salt'])) + { + // create a random salt for this session if a cookie doesn't already exist for it + $_SESSION[COOKIENAME.'_salt'] = self::generateSalt(22); + } + else if(!isset($_SESSION[COOKIENAME.'_salt']) && isset($_COOKIE[COOKIENAME.'_salt'])) + { + // session doesn't exist, but cookie does so grab it + $_SESSION[COOKIENAME.'_salt'] = $_COOKIE[COOKIENAME.'_salt']; + } + + // salted and encrypted password used for checking + $this->system_password_encrypted = md5(SYSTEMPASSWORD."_".$_SESSION[COOKIENAME.'_salt']); + + $this->authorized = + // no password + SYSTEMPASSWORD == '' + // correct password stored in session + || isset($_SESSION[COOKIENAME.'password']) && hash_equals($_SESSION[COOKIENAME.'password'], $this->system_password_encrypted) + // correct password stored in cookie + || isset($_COOKIE[COOKIENAME]) && isset($_COOKIE[COOKIENAME.'_salt']) && hash_equals(md5(SYSTEMPASSWORD."_".$_COOKIE[COOKIENAME.'_salt']), $_COOKIE[COOKIENAME]); + } + + public function attemptGrant($password, $remember) + { + $hashed_password = crypt(SYSTEMPASSWORD, '$2a$07$'.self::generateSalt(22).'$'); + if (hash_equals($hashed_password, crypt($password, $hashed_password))) { + if ($remember) { + // user wants to be remembered, so set a cookie + $expire = time()+60*60*24*30; //set expiration to 1 month from now + setcookie(COOKIENAME, $this->system_password_encrypted, $expire, null, null, null, true); + setcookie(COOKIENAME."_salt", $_SESSION[COOKIENAME.'_salt'], $expire, null, null, null, true); + } else { + // user does not want to be remembered, so destroy any potential cookies + setcookie(COOKIENAME, "", time()-86400, null, null, null, true); + setcookie(COOKIENAME."_salt", "", time()-86400, null, null, null, true); + unset($_COOKIE[COOKIENAME]); + unset($_COOKIE[COOKIENAME.'_salt']); + } + + $_SESSION[COOKIENAME.'password'] = $this->system_password_encrypted; + $this->authorized = true; + return true; + } + + $this->login_failed = true; + return false; + } + + public function revoke() + { + //destroy everything - cookies and session vars + setcookie(COOKIENAME, "", time()-86400, null, null, null, true); + setcookie(COOKIENAME."_salt", "", time()-86400, null, null, null, true); + unset($_COOKIE[COOKIENAME]); + unset($_COOKIE[COOKIENAME.'_salt']); + session_unset(); + session_destroy(); + $this->authorized = false; + // start a new session and generate a new CSRF token for the login form + session_start(); + $this->generateToken(); + } + + public function isAuthorized() + { + return $this->authorized; + } + + public function isFailedLogin() + { + return $this->login_failed; + } + + public function isPasswordDefault() + { + return SYSTEMPASSWORD == 'admin'; + } + + private static function generateSalt($saltSize) + { + $set = 'ABCDEFGHiJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + $setLast = strlen($set) - 1; + $salt = ''; + while ($saltSize-- > 0) { + $salt .= $set[mt_rand(0, $setLast)]; + } + return $salt; + } + + private function generateToken() + { + // generate CSRF token + if (empty($_SESSION[COOKIENAME.'token'])) + { + if (function_exists('random_bytes')) // introduced in PHP 7.0 + { + $_SESSION[COOKIENAME.'token'] = bin2hex(random_bytes(32)); + } + elseif (function_exists('openssl_random_pseudo_bytes')) // introduced in PHP 5.3.0 + { + $_SESSION[COOKIENAME.'token'] = bin2hex(openssl_random_pseudo_bytes(32)); + } + else + { + // For PHP 5.2.x - This case can be removed once we drop support for 5.2.x + $_SESSION[COOKIENAME.'token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); + } + } + } + + private function checkToken() + { + // checking CSRF token + if($_SERVER['REQUEST_METHOD'] === 'POST' || isset($_GET['download'])) // all POST forms need tokens! downloads are protected as well + { + if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['token'])) + $check_token=$_POST['token']; + elseif($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['token'])) + $check_token=$_GET['token']; + + if (!isset($check_token)) + { + die("CSRF token missing"); + } + elseif(!hash_equals($_SESSION[COOKIENAME.'token'], $check_token)) + { + die("CSRF token is wrong - please try to login again"); + } + } + } + +} +// Database class +// Generic database abstraction class to manage interaction with database without worrying about SQLite vs. PHP versions +// +class Database +{ + protected $db; //reference to the DB object + protected $type; //the extension for PHP that handles SQLite + protected $data; + protected $lastResult; + protected $alterError; + protected $debugOutput =''; + + public function __construct($data) + { + global $lang, $params; + $this->data = $data; + try + { + if(!file_exists($this->data["path"]) && !is_writable(dirname($this->data["path"]))) //make sure the containing directory is writable if the database does not exist + { + echo "
"; + printf($lang['db_not_writeable'], htmlencode($this->data["path"]), htmlencode(dirname($this->data["path"]))); + echo $params->getForm(); + echo ""; + echo ""; + echo "

"; + exit(); + } + + $ver = $this->getVersion(); + + switch(true) + { + case ((!isset($data['type']) || $data['type']!=2) && (FORCETYPE=="PDO" || (FORCETYPE==false && class_exists("PDO") && in_array("sqlite", PDO::getAvailableDrivers()) && ($ver==-1 || $ver==3)))): + $this->db = new PDO("sqlite:".$this->data['path']); + if($this->db!=NULL) + { + $this->type = "PDO"; + break; + } + case ((!isset($data['type']) || $data['type']!=2) && (FORCETYPE=="SQLite3" || (FORCETYPE==false && class_exists("SQLite3") && ($ver==-1 || $ver==3)))): + $this->db = new SQLite3($this->data['path']); + if($this->db!=NULL) + { + $this->type = "SQLite3"; + break; + } + case (FORCETYPE=="SQLiteDatabase" || (FORCETYPE==false && class_exists("SQLiteDatabase") && ($ver==-1 || $ver==2))): + $this->db = new SQLiteDatabase($this->data['path']); + if($this->db!=NULL) + { + $this->type = "SQLiteDatabase"; + break; + } + default: + $this->showError(); + exit(); + } + $this->query("PRAGMA foreign_keys = ON"); + } + catch(Exception $e) + { + $this->showError(); + exit(); + } + } + + public function registerUserFunction($ids) + { + // in case a single function id was passed + if (is_string($ids)) + $ids = array($ids); + + if ($this->type == 'PDO') { + foreach ($ids as $id) { + $this->db->sqliteCreateFunction($id, $id, -1); + } + } else { // type is Sqlite3 or SQLiteDatabase + foreach ($ids as $id) { + $this->db->createFunction($id, $id, -1); + } + } + } + + public function getError($complete_msg = false) + { + global $lang, $debug; + $error = "unknown"; + + if($this->alterError!='') + { + $error = $this->alterError; + $this->alterError = ""; + } + else if($this->type=="PDO") + { + $e = $this->db->errorInfo(); + $error = $e[2]; + } + else if($this->type=="SQLite3") + { + $error = $this->db->lastErrorMsg(); + } + else + { + $error = sqlite_error_string($this->db->lastError()); + } + + if($complete_msg) + { + $error = $lang['err'].": ".htmlencode($error); + // do not suggest to report a bug when constraints fail + if(strpos($error, 'constraint failed')===false) + $error.="
".$lang['bug_report'].' '.PROJECT_BUGTRACKER_LINK; + } + + if($debug) + $error .= $this->getDebugOutput(); + + return $error; + } + + function getDebugOutput() + { + return ($this->debugOutput != "" ? "
DEBUG:
".$this->debugOutput : $this->debugOutput); + } + + public function showError() + { + global $lang; + $classPDO = class_exists("PDO"); + $classSQLite3 = class_exists("SQLite3"); + $classSQLiteDatabase = class_exists("SQLiteDatabase"); + if($classPDO) // PDO is there, check if the SQLite driver for PDO is missing + $PDOSqliteDriver = (in_array("sqlite", PDO::getAvailableDrivers() )); + else + $PDOSqliteDriver = false; + echo "
"; + printf($lang['db_setup'], $this->getPath()); + echo ".

".$lang['chk_ext']."...

"; + echo "PDO: ".($classPDO ? $lang['installed'] : $lang['not_installed'])."
"; + echo "PDO SQLite Driver: ".($PDOSqliteDriver ? $lang['installed'] : $lang['not_installed'])."
"; + echo "SQLite3: ".($classSQLite3 ? $lang['installed'] : $lang['not_installed'])."
"; + echo "SQLiteDatabase: ".($classSQLiteDatabase ? $lang['installed'] : $lang['not_installed'])."
"; + echo "
...".$lang['done'].".


"; + if(!$classPDO && !$classSQLite3 && !$classSQLiteDatabase) + printf($lang['sqlite_ext_support'], PROJECT); + else + { + if(!$PDOSqliteDriver && !$classSQLite3 && $this->getVersion()==3) + printf($lang['sqlite_v_error'], 3, PROJECT, 2); + else if(!$classSQLiteDatabase && $this->getVersion()==2) + printf($lang['sqlite_v_error'], 2, PROJECT, 3); + else + echo $lang['report_issue'].' '.PROJECT_BUGTRACKER_LINK.'.'; + } + echo "

See ".PROJECT_INSTALL_LINK." for help.

"; + + $this->print_db_list(); + + echo "
"; + } + + // print the list of databases + public function print_db_list() + { + global $databases, $lang, $params, $currentDB; + echo "
".$lang['db_ch'].""; + if(sizeof($databases)<10) //if there aren't a lot of databases, just show them as a list of links instead of drop down menu + { + $i=0; + foreach($databases as $database) + { + $i++; + $name = $database['name']; + if(mb_strlen($name)>25) + $name = "...".mb_substr($name, mb_strlen($name)-22, 22); + echo '[' . ($database['readable'] ? 'r':' ' ) . ($database['writable'] && $database['writable_dir'] ? 'w':' ' ) . '] '; + + echo $params->getLink(array('database'=>$database['path'], 'table'=>null), htmlencode($name), ($database == $currentDB? 'active_db': '') ); + echo "  "; + echo $params->getLink(array('download'=>$database['path'], 'table'=>null, 'token'=>$_SESSION[COOKIENAME.'token']), '[↓]', '', $lang['backup']); + + if($i"; + } + } + else //there are a lot of databases - show a drop down menu + { + echo $params->getForm(array('table'=>null), 'get'); + echo ""; + echo ""; + echo ""; + } + echo "
"; + } + + public function __destruct() + { + if($this->db) + $this->close(); + } + + //get the exact PHP extension being used for SQLite + public function getType() + { + return $this->type; + } + + // get the version of the SQLite library + public function getSQLiteVersion() + { + $queryVersion = $this->select("SELECT sqlite_version() AS sqlite_version"); + return $queryVersion['sqlite_version']; + } + + //get the name of the database + public function getName() + { + return $this->data["name"]; + } + + //get the filename of the database + public function getPath() + { + return $this->data["path"]; + } + + //is the db-file writable? + public function isWritable() + { + return $this->data["writable"]; + } + + //is the db-folder writable? + public function isDirWritable() + { + return $this->data["writable_dir"]; + } + + //get the version of the database + public function getVersion() + { + if(file_exists($this->data['path'])) //make sure file exists before getting its contents + { + $content = strtolower(file_get_contents($this->data['path'], NULL, NULL, 0, 40)); //get the first 40 characters of the database file + $p = strpos($content, "** this file contains an sqlite 2"); //this text is at the beginning of every SQLite2 database + if($p!==false) //the text is found - this is version 2 + return 2; + else + return 3; + } + else //return -1 to indicate that it does not exist and needs to be created + { + return -1; + } + } + + //get the size of the database (in KiB) + public function getSize() + { + return round(filesize($this->data["path"])*0.0009765625, 1); + } + + //get the last modified time of database + public function getDate() + { + global $lang; + return date($lang['date_format'], filemtime($this->data['path'])); + } + + //get number of affected rows from last query + public function getAffectedRows() + { + if($this->type=="PDO") + if(!is_object($this->lastResult)) + // in case it was an alter table statement, there is no lastResult object + return 0; + else + return $this->lastResult->rowCount(); + else if($this->type=="SQLite3") + return $this->db->changes(); + else if($this->type=="SQLiteDatabase") + return $this->db->changes(); + } + + public function getTypeOfTable($table) + { + $result = $this->select("SELECT `type` FROM `sqlite_master` WHERE `name`=" . $this->quote($table), 'assoc'); + return $result['type']; + } + + public function getTableInfo($table) + { + return $this->selectArray("PRAGMA table_info(".$this->quote_id($table).")"); + } + + // returns the list of tables (opt. incl. views) as + // array( Tablename => tableType ) with tableType being 'view' or 'table' + public function getTables($alsoViews=true, $alsoInternal=false, $orderBy='name', $orderDirection='ASC') + { + $query = "SELECT name, type FROM sqlite_master " + . "WHERE (type='table'".($alsoViews?" OR type='view'":"").") " + . "AND name!='' ".($alsoInternal? "":" AND name NOT LIKE 'sqlite_%' ") + . "ORDER BY ".$this->quote_id($orderBy)." ".$orderDirection; + $result = $this->selectArray($query); + $list = array(); + for($i=0; $i array(columName) ) + public function getTableDefinitions() + { + $tables = $this->getTables(true, true); + $result = array(); + foreach ($tables as $tableName => $tableType) + { + $tableInfo = $this->getTableInfo($tableName); + $columns = array(); + foreach($tableInfo as $column) + $columns[] = $column['name']; + $result[$tableName] = $columns; + } + return $result; + } + + public function close() + { + if($this->type=="PDO") + $this->db = NULL; + else if($this->type=="SQLite3") + $this->db->close(); + else if($this->type=="SQLiteDatabase") + $this->db = NULL; + } + + public function beginTransaction() + { + $this->query("BEGIN"); + } + + public function commitTransaction() + { + $this->query("COMMIT"); + } + + public function rollbackTransaction() + { + $this->query("ROLLBACK"); + } + + //generic query wrapper + //returns false on error and the query result on success + public function query($query, $ignoreAlterCase=false) + { + global $debug; + if(strtolower(substr(ltrim($query),0,5))=='alter' && $ignoreAlterCase==false) //this query is an ALTER query - call the necessary function + { + preg_match("/^\s*ALTER\s+TABLE\s+\"((?:[^\"]|\"\")+)\"\s+(.*)$/i",$query,$matches); + if(!isset($matches[1]) || !isset($matches[2])) + { + if($debug) echo "SQL?
"; + return false; + } + $tablename = str_replace('""','"',$matches[1]); + $alterdefs = $matches[2]; + if($debug) echo "ALTER TABLE QUERY=(".htmlencode($query)."), tablename=($tablename), alterdefs=($alterdefs)
"; + $result = $this->alterTable($tablename, $alterdefs); + } + else //this query is normal - proceed as normal + { + $result = $this->db->query($query); + if($debug) echo "SQL?
"; + } + if($result===false) + return false; + $this->lastResult = $result; + return $result; + } + + //wrapper for an INSERT and returns the ID of the inserted row + public function insert($query) + { + $result = $this->query($query); + if($this->type=="PDO") + return $this->db->lastInsertId(); + else if($this->type=="SQLite3") + return $this->db->lastInsertRowID(); + else if($this->type=="SQLiteDatabase") + return $this->db->lastInsertRowid(); + } + + //returns an array for SELECT + public function select($query, $mode="both") + { + $result = $this->query($query); + if(!$result) //make sure the result is valid + return NULL; + if($this->type=="PDO") + { + if($mode=="assoc") + $mode = PDO::FETCH_ASSOC; + else if($mode=="num") + $mode = PDO::FETCH_NUM; + else + $mode = PDO::FETCH_BOTH; + $ret = $result->fetch($mode); + $result->closeCursor(); + return $ret; + } + else if($this->type=="SQLite3") + { + if($mode=="assoc") + $mode = SQLITE3_ASSOC; + else if($mode=="num") + $mode = SQLITE3_NUM; + else + $mode = SQLITE3_BOTH; + $ret = $result->fetchArray($mode); + $result->finalize(); + return $ret; + } + else if($this->type=="SQLiteDatabase") + { + if($mode=="assoc") + $mode = SQLITE_ASSOC; + else if($mode=="num") + $mode = SQLITE_NUM; + else + $mode = SQLITE_BOTH; + return $result->fetch($mode); + } + } + + //returns an array of arrays after doing a SELECT + public function selectArray($query, $mode="both") + { + $result = $this->query($query); + //make sure the result is valid + if($result=== false || $result===NULL) + return NULL; // error + if(!is_object($result)) // no rows returned + return array(); + if($this->type=="PDO") + { + if($mode=="assoc") + $mode = PDO::FETCH_ASSOC; + else if($mode=="num") + $mode = PDO::FETCH_NUM; + else + $mode = PDO::FETCH_BOTH; + $ret = $result->fetchAll($mode); + $result->closeCursor(); + return $ret; + } + else if($this->type=="SQLite3") + { + if($mode=="assoc") + $mode = SQLITE3_ASSOC; + else if($mode=="num") + $mode = SQLITE3_NUM; + else + $mode = SQLITE3_BOTH; + $arr = array(); + $i = 0; + while($res = $result->fetchArray($mode)) + { + $arr[$i] = $res; + $i++; + } + $result->finalize(); + return $arr; + } + else if($this->type=="SQLiteDatabase") + { + if($mode=="assoc") + $mode = SQLITE_ASSOC; + else if($mode=="num") + $mode = SQLITE_NUM; + else + $mode = SQLITE_BOTH; + return $result->fetchAll($mode); + } + } + + //returns an array of the next row in $result + public function fetch($result, $mode="both") + { + //make sure the result is valid + if($result=== false || $result===NULL) + return NULL; // error + if(!is_object($result)) // no rows returned + return array(); + if($this->type=="PDO") + { + if($mode=="assoc") + $mode = PDO::FETCH_ASSOC; + else if($mode=="num") + $mode = PDO::FETCH_NUM; + else + $mode = PDO::FETCH_BOTH; + return $result->fetch($mode); + } + else if($this->type=="SQLite3") + { + if($mode=="assoc") + $mode = SQLITE3_ASSOC; + else if($mode=="num") + $mode = SQLITE3_NUM; + else + $mode = SQLITE3_BOTH; + return $result->fetchArray($mode); + } + else if($this->type=="SQLiteDatabase") + { + if($mode=="assoc") + $mode = SQLITE_ASSOC; + else if($mode=="num") + $mode = SQLITE_NUM; + else + $mode = SQLITE_BOTH; + return $result->fetch($mode); + } + } + + public function getColumnName($result, $colNum) + { + //make sure the result is valid + if($result=== false || $result===NULL || !is_object($result)) + return ""; // error or no rows returned + if($this->type=="PDO") + { + $meta = $result->getColumnMeta($colNum); + return $meta['name']; + } + else if($this->type=="SQLite3") + { + return $result->columnName($colNum); + } + else if($this->type=="SQLiteDatabase") + { + return $result->fieldName($colNum); + } + } + + + // SQlite supports multiple ways of surrounding names in quotes: + // single-quotes, double-quotes, backticks, square brackets. + // As sqlite does not keep this strict, we also need to be flexible here. + // This function generates a regex that matches any of the possibilities. + private function sqlite_surroundings_preg($name,$preg_quote=true,$notAllowedCharsIfNone="'\"",$notAllowedName=false) + { + if($name=="*" || $name=="+") + { + if($notAllowedName!==false && $preg_quote) + $notAllowedName = preg_quote($notAllowedName,"/"); + // use possesive quantifiers to save memory + // (There is a bug in PCRE starting in 8.13 and fixed in PCRE 8.36 + // why we can't use posesive quantifiers - See issue #310). + if(version_compare(strstr(constant('PCRE_VERSION'), ' ', true), '8.36', '>=') || + version_compare(strstr(constant('PCRE_VERSION'), ' ', true), '8.12', '<=')) + $posessive='+'; + else + $posessive=''; + + $nameSingle = ($notAllowedName!==false?"(?!".$notAllowedName."')":"")."(?:[^']$name+|'')$name".$posessive; + $nameDouble = ($notAllowedName!==false?"(?!".$notAllowedName."\")":"")."(?:[^\"]$name+|\"\")$name".$posessive; + $nameBacktick = ($notAllowedName!==false?"(?!".$notAllowedName."`)":"")."(?:[^`]$name+|``)$name".$posessive; + $nameSquare = ($notAllowedName!==false?"(?!".$notAllowedName."\])":"")."(?:[^\]]$name+|\]\])$name".$posessive; + $nameNo = ($notAllowedName!==false?"(?!".$notAllowedName."\s)":"")."[^".$notAllowedCharsIfNone."]$name"; + } + else + { + if($preg_quote) $name = preg_quote($name,"/"); + + $nameSingle = str_replace("'","''",$name); + $nameDouble = str_replace('"','""',$name); + $nameBacktick = str_replace('`','``',$name); + $nameSquare = str_replace(']',']]',$name); + $nameNo = $name; + } + + $preg = "(?:'".$nameSingle."'|". // single-quote surrounded or not in quotes (correct SQL for values/new names) + $nameNo."|". // not surrounded (correct SQL if not containing reserved words, spaces or some special chars) + "\"".$nameDouble."\"|". // double-quote surrounded (correct SQL for identifiers) + "`".$nameBacktick."`|". // backtick surrounded (MySQL-Style) + "\[".$nameSquare."\])"; // square-bracket surrounded (MS Access/SQL server-Style) + return $preg; + } + + // Returns the last PREG error as a string, '' if no error occured + private function getPregError() + { + $error = preg_last_error(); + switch ($error) + { + case PREG_NO_ERROR: return 'No error'; + case PREG_INTERNAL_ERROR: return 'There is an internal error!'; + case PREG_BACKTRACK_LIMIT_ERROR: return 'Backtrack limit was exhausted!'; + case PREG_RECURSION_LIMIT_ERROR: return 'Recursion limit was exhausted!'; + case PREG_BAD_UTF8_ERROR: return 'Bad UTF8 error!'; + // PREG_BAD_UTF8_OFFSET_ERROR is introduced in PHP 5.3.0, which is not yet required by PLA, so we use its value 5 instead so long + case 5: return 'Bad UTF8 offset error!'; + default: return 'Unknown Error'; + } + } + + // function that is called for an alter table statement in a query + // code borrowed with permission from http://code.jenseng.com/db/ + // this has been completely debugged / rewritten by Christopher Kramer + public function alterTable($table, $alterdefs) + { + global $debug, $lang; + $this->alterError=""; + $errormsg = sprintf($lang['alter_failed'],htmlencode($table)).' - '; + if($debug) $this->debugOutput .= "ALTER TABLE: table=($table), alterdefs=($alterdefs), PCRE version=(".PCRE_VERSION.")

"; + if($alterdefs != '') + { + $recreateQueries = array(); + $resultArr = $this->selectArray("SELECT sql,name,type FROM sqlite_master WHERE tbl_name = ".$this->quote($table)); + if(sizeof($resultArr)<1) + { + $this->alterError = $errormsg . sprintf($lang['tbl_inexistent'], htmlencode($table)); + if($debug) $this->debugOutput .= "ERROR: unknown table

"; + return false; + } + for($i=0; $idebugOutput .= "recreate=(".$row['sql'].";)
"; + } + } + elseif($row['type']=='view') // workaround to rename views + { + $origsql = $row['sql']; + $preg_remove_create_view = "/^\s*+CREATE\s++VIEW\s++".$this->sqlite_surroundings_preg($table)."\s*+(AS\s++SELECT\s++.*+)$/is"; + $origsql_no_create = preg_replace($preg_remove_create_view, '$1', $origsql, 1); + if($debug) $this->debugOutput .= "origsql=($origsql)
preg_remove_create_table=($preg_remove_create_view)
"; + preg_match("/RENAME\s++TO\s++(?:\"((?:[^\"]|\"\")+)\"|'((?:[^']|'')+)')/is", $alterdefs, $matches); + if(isset($matches[1]) && $matches[1]!='') + $newname = $matches[1]; + elseif(isset($matches[2]) && $matches[2]!='') + $newname = $matches[2]; + else + { + $this->alterError = $errormsg . ' could not detect new view name. It needs to be in single or double quotes.'; + if($debug) $this->debugOutput .= "ERROR: could not detect new view name
"; + return false; + } + $dropoldSQL = 'DROP VIEW '.$this->quote_id($table); + $createnewSQL = 'CREATE VIEW '.$this->quote_id($newname).' '.$origsql_no_create; + $alter_transaction = 'BEGIN; ' . $dropoldSQL .'; '. $createnewSQL . '; ' . 'COMMIT;'; + if($debug) $this->debugOutput .= $alter_transaction; + return $this->multiQuery($alter_transaction); + } + else + { + // ALTER the table + $tmpname = 't'.time(); + $origsql = $row['sql']; + $preg_remove_create_table = "/^\s*+CREATE\s++TABLE\s++".$this->sqlite_surroundings_preg($table)."\s*+(\(.*+)$/is"; + $origsql_no_create = preg_replace($preg_remove_create_table, '$1', $origsql, 1); + if($debug) $this->debugOutput .= "origsql=($origsql)
preg_remove_create_table=($preg_remove_create_table)
"; + if($origsql_no_create == $origsql) + { + $this->alterError = $errormsg . $lang['alter_tbl_name_not_replacable']; + if($debug) $this->debugOutput .= "ERROR: could not get rid of CREATE TABLE
"; + return false; + } + $createtemptableSQL = "CREATE TABLE ".$this->quote($tmpname)." ".$origsql_no_create; + if($debug) $this->debugOutput .= "createtemptableSQL=($createtemptableSQL)
"; + $createindexsql = array(); + $preg_alter_part = "/(?:DROP(?! PRIMARY KEY)|ADD(?! PRIMARY KEY)|CHANGE|RENAME TO|ADD PRIMARY KEY|DROP PRIMARY KEY)" // the ALTER command + ."(?:" + ."\s+\(".$this->sqlite_surroundings_preg("+",false,"\"'\[`)")."+\)" // stuff in brackets (in case of ADD PRIMARY KEY) + ."|" // or + ."\s+".$this->sqlite_surroundings_preg("+",false,",'\"\[`") // column names and stuff like this + .")*/i"; + if($debug) + $this->debugOutput .= "preg_alter_part=(".$preg_alter_part.")
"; + preg_match_all($preg_alter_part,$alterdefs,$matches); + $defs = $matches[0]; + + $result_oldcols = $this->getTableInfo($table); + $newcols = array(); + $coltypes = array(); + $primarykey = array(); + foreach($result_oldcols as $column_info) + { + $newcols[$column_info['name']] = $column_info['name']; + $coltypes[$column_info['name']] = $column_info['type']; + if($column_info['pk']) + $primarykey[] = $column_info['name']; + } + $newcolumns = ''; + $oldcolumns = ''; + reset($newcols); + while(list($key, $val) = each($newcols)) + { + $newcolumns .= ($newcolumns?', ':'').$this->quote_id($val); + $oldcolumns .= ($oldcolumns?', ':'').$this->quote_id($key); + } + $copytotempsql = 'INSERT INTO '.$this->quote_id($tmpname).'('.$newcolumns.') SELECT '.$oldcolumns.' FROM '.$this->quote_id($table); + $dropoldsql = 'DROP TABLE '.$this->quote_id($table); + $createtesttableSQL = $createtemptableSQL; + if(count($defs)<1) + { + $this->alterError = $errormsg . $lang['alter_no_def']; + if($debug) $this->debugOutput .= "ERROR: defs<1

"; + return false; + } + foreach($defs as $def) + { + if($debug) $this->debugOutput .= "
def=$def
"; + $preg_parse_def = + "/^(DROP(?! PRIMARY KEY)|ADD(?! PRIMARY KEY)|CHANGE|RENAME TO|ADD PRIMARY KEY|DROP PRIMARY KEY)" // $matches[1]: command + ."(?:" // this is either + ."(?:\s+\((.+)\)\s*$)" // anything in brackets (for ADD PRIMARY KEY) + // then $matches[2] is what there is in brackets + ."|" // OR: + ."(?:\s+\"((?:[^\"]|\"\")+)\"|\s+'((?:[^']|'')+)')"// (first) column name, either in single or double quotes + // in case of RENAME TO, it is the new a table name + // $matches[3] will be the column/table name without the quotes if double quoted + // $matches[4] will be the column/table name without the quotes if single quoted + ."(" // $matches[5]: anything after the column name + ."(?:\s+'((?:[^']|'')+)')?" // $matches[6] (optional): a second column name surrounded with single quotes + // (the match does not contain the quotes) + ."\s*" + ."((?:[A-Z]+\s*)+(?:\(\s*[+-]?\s*[0-9]+(?:\s*,\s*[+-]?\s*[0-9]+)?\s*\))?)?\s*" // $matches[7] (optional): a type name + .".*". + ")" + ."?\s*$" + .")?\s*$/i"; // in case of DROP PRIMARY KEY, there is nothing after the command + if($debug) $this->debugOutput .= "preg_parse_def=$preg_parse_def
"; + $parse_def = preg_match($preg_parse_def,$def,$matches); + if($parse_def===false) + { + $this->alterError = $errormsg . $lang['alter_parse_failed']; + if($debug) $this->debugOutput .= "ERROR: !parse_def

"; + return false; + } + if(!isset($matches[1])) + { + $this->alterError = $errormsg . $lang['alter_action_not_recognized']; + if($debug) $this->debugOutput .= "ERROR: !isset(matches[1])

"; + return false; + } + $action = strtolower($matches[1]); + if(($action == 'add' || $action == 'rename to') && isset($matches[4]) && $matches[4]!='') + $column = str_replace("''","'",$matches[4]); // enclosed in '' + elseif($action == 'add primary key' && isset($matches[2]) && $matches[2]!='') + $column = $matches[2]; + elseif($action == 'drop primary key') + $column = ''; // DROP PRIMARY KEY has no column definition + elseif(isset($matches[3]) && $matches[3]!='') + $column = str_replace('""','"',$matches[3]); // enclosed in "" + else + $column = ''; + + $column_escaped = str_replace("'","''",$column); + + if($debug) $this->debugOutput .= "action=($action), column=($column), column_escaped=($column_escaped)
"; + + /* we build a regex that devides the CREATE TABLE statement parts: + Part example Group Explanation + 1. CREATE TABLE t... ( $1 + 2. 'col1' ..., 'col2' ..., 'colN' ..., $3 (with col1-colN being columns that are not changed and listed before the col to change) + 3. 'colX' ..., (with colX being the column to change/drop) + 4. 'colX+1' ..., ..., 'colK') $5 (with colX+1-colK being columns after the column to change/drop) + */ + $preg_create_table = "\s*+(CREATE\s++TABLE\s++".preg_quote($this->quote($tmpname),"/")."\s*+\()"; // This is group $1 (keep unchanged) + $preg_column_definiton = "\s*+".$this->sqlite_surroundings_preg("+",true," '\"\[`,",$column)."(?:\s*+".$this->sqlite_surroundings_preg("*",false,"'\",`\[ ").")++"; // catches a complete column definition, even if it is + // 'column' TEXT NOT NULL DEFAULT 'we have a comma, here and a double ''quote!' + // this definition does NOT match columns with the column name $column + if($debug) $this->debugOutput .= "preg_column_definition=(".$preg_column_definiton.")
"; + $preg_columns_before = // columns before the one changed/dropped (keep) + "(?:". + "(". // group $2. Keep this one unchanged! + "(?:". + "$preg_column_definiton,\s*+". // column definition + comma + ")*". // there might be any number of such columns here + $preg_column_definiton. // last column definition + ")". // end of group $2 + ",\s*+" // the last comma of the last column before the column to change. Do not keep it! + .")?"; // there might be no columns before + if($debug) $this->debugOutput .= "preg_columns_before=(".$preg_columns_before.")
"; + $preg_columns_after = "(,\s*(.+))?"; // the columns after the column to drop. This is group $3 (drop) or $4(change) (keep!) + // we could remove the comma using $6 instead of $5, but then we might have no comma at all. + // Keeping it leaves a problem if we drop the first column, so we fix that case in another regex. + $table_new = $table; + + switch($action) + { + case 'add': + if($column=='') + { + $this->alterError = $errormsg . ' (add) - '. $lang['alter_no_add_col']; + return false; + } + $new_col_definition = "'$column_escaped' ".(isset($matches[5])?$matches[5]:''); + $preg_pattern_add = "/^".$preg_create_table. // the CREATE TABLE statement ($1) + "((?:(?!,\s*(?:PRIMARY\s+KEY\s*\(|CONSTRAINT\s|UNIQUE\s*\(|CHECK\s*\(|FOREIGN\s+KEY\s*\()).)*)". // column definitions ($2) + "(.*)\\)\s*$/si"; // table-constraints like PRIMARY KEY(a,b) ($3) and the closing bracket + // append the column definiton in the CREATE TABLE statement + $newSQL = preg_replace($preg_pattern_add, '$1$2, '.strtr($new_col_definition, array('\\' => '\\\\', '$' => '\$')).' $3', $createtesttableSQL).')'; + $preg_error = $this->getPregError(); + if($debug) + { + $this->debugOutput .= $createtesttableSQL."

"; + $this->debugOutput .= $newSQL."

"; + $this->debugOutput .= $preg_pattern_add."

"; + } + if($newSQL==$createtesttableSQL) // pattern did not match, so column adding did not succed + { + $this->alterError = $errormsg . ' (add) - '.$lang['alter_pattern_mismatch'].'. PREG ERROR: '.$preg_error; + return false; + } + $createtesttableSQL = $newSQL; + break; + case 'change': + var_dump($matches); + if(!isset($matches[6])) + { + $this->alterError = $errormsg . ' (change) - '.$lang['alter_col_not_recognized']; + return false; + } + $new_col_name = $matches[6]; + if(!isset($matches[7])) + $new_col_type = ''; + else + $new_col_type = $matches[7]; + $new_col_definition = "'$new_col_name' $new_col_type"; + $preg_column_to_change = "\s*".$this->sqlite_surroundings_preg($column)."(?:\s+".preg_quote($coltypes[$column]).")?(\s+(?:".$this->sqlite_surroundings_preg("*",false,",'\"`\[").")+)?"; + // replace this part (we want to change this column) + // group $3 contains the column constraints (keep!). the name & data type is replaced. + $preg_pattern_change = "/^".$preg_create_table.$preg_columns_before.$preg_column_to_change.$preg_columns_after."\s*\\)\s*$/s"; + + // replace the column definiton in the CREATE TABLE statement + $newSQL = preg_replace($preg_pattern_change, '$1$2,'.strtr($new_col_definition, array('\\' => '\\\\', '$' => '\$')).'$3$4)', $createtesttableSQL); + $preg_error = $this->getPregError(); + // remove comma at the beginning if the first column is changed + // probably somebody is able to put this into the first regex (using lookahead probably). + $newSQL = preg_replace("/^\s*(CREATE\s+TABLE\s+".preg_quote($this->quote($tmpname),"/")."\s+\(),\s*/",'$1',$newSQL); + if($debug) + { + $this->debugOutput .= "preg_column_to_change=(".$preg_column_to_change.")

"; + $this->debugOutput .= $createtesttableSQL."

"; + $this->debugOutput .= $newSQL."

"; + + $this->debugOutput .= $preg_pattern_change."

"; + } + if($newSQL==$createtesttableSQL || $newSQL=="") // pattern did not match, so column removal did not succed + { + $this->alterError = $errormsg . ' (change) - '.$lang['alter_pattern_mismatch'].'. PREG ERROR: '.$preg_error; + return false; + } + $createtesttableSQL = $newSQL; + $newcols[$column] = str_replace("''","'",$new_col_name); + break; + case 'drop': + $preg_column_to_drop = "\s*".$this->sqlite_surroundings_preg($column)."\s+(?:".$this->sqlite_surroundings_preg("*",false,",'\"\[`").")+"; // delete this part (we want to drop this column) + $preg_pattern_drop = "/^".$preg_create_table.$preg_columns_before.$preg_column_to_drop.$preg_columns_after."\s*\\)\s*$/s"; + + // remove the column out of the CREATE TABLE statement + $newSQL = preg_replace($preg_pattern_drop, '$1$2$3)', $createtesttableSQL); + $preg_error = $this->getPregError(); + // remove comma at the beginning if the first column is removed + // probably somebody is able to put this into the first regex (using lookahead probably). + $newSQL = preg_replace("/^\s*(CREATE\s+TABLE\s+".preg_quote($this->quote($tmpname),"/")."\s+\(),\s*/",'$1',$newSQL); + if($debug) + { + $this->debugOutput .= $createtesttableSQL."

"; + $this->debugOutput .= $newSQL."

"; + $this->debugOutput .= $preg_pattern_drop."

"; + } + if($newSQL==$createtesttableSQL || $newSQL=="") // pattern did not match, so column removal did not succed + { + $this->alterError = $errormsg . ' (drop) - '.$lang['alter_pattern_mismatch'].'. PREG ERROR: '.$preg_error; + return false; + } + $createtesttableSQL = $newSQL; + unset($newcols[$column]); + break; + case 'rename to': + // don't change column definition at all + $newSQL = $createtesttableSQL; + // only change the name of the table + $table_new = $column; + break; + case 'add primary key': + // we want to add a primary key for the column(s) stored in $column + $newSQL = preg_replace("/\)\s*$/", ", PRIMARY KEY (".$column.") )", $createtesttableSQL); + $createtesttableSQL = $newSQL; + break; + case 'drop primary key': + // we want to drop the primary key + if($debug) $this->debugOutput .= "DROP"; + if(sizeof($primarykey)==1) + { + // if not compound primary key, might be a column constraint -> try removal + $column = $primarykey[0]; + if($debug) $this->debugOutput .= "
Trying to drop column constraint for column $column
"; + /* + TODO: This does not work yet: + CREATE TABLE 't12' ('t1' INTEGER CONSTRAINT "bla" NOT NULL CONSTRAINT 'pk' PRIMARY KEY ); ALTER TABLE "t12" DROP PRIMARY KEY + This does: ! ! + CREATE TABLE 't12' ('t1' INTEGER CONSTRAINT bla NOT NULL CONSTRAINT 'pk' PRIMARY KEY ); ALTER TABLE "t12" DROP PRIMARY KEY + */ + $preg_column_to_change = "(\s*".$this->sqlite_surroundings_preg($column).")". // column ($3) + "(?:". // opt. type and column constraints + "(\s+(?:".$this->sqlite_surroundings_preg("(?:[^PC,'\"`\[]|P(?!RIMARY\s+KEY)|". + "C(?!ONSTRAINT\s+".$this->sqlite_surroundings_preg("+",false," ,'\"\[`")."\s+PRIMARY\s+KEY))",false,",'\"`\[").")*)". // column constraints before PRIMARY KEY ($3) + // primary key constraint (remove this!): + "(?:CONSTRAINT\s+".$this->sqlite_surroundings_preg("+",false," ,'\"\[`")."\s+)?". + "PRIMARY\s+KEY". + "(?:\s+(?:ASC|DESC))?". + "(?:\s+ON\s+CONFLICT\s+(?:ROLLBACK|ABORT|FAIL|IGNORE|REPLACE))?". + "(?:\s+AUTOINCREMENT)?". + "((?:".$this->sqlite_surroundings_preg("*",false,",'\"`\[").")*)". // column constraints after PRIMARY KEY ($4) + ")"; + // replace this part (we want to change this column) + // group $3 (column) $4 (constraints before) and $5 (constraints after) contain the part to keep + $preg_pattern_change = "/^".$preg_create_table.$preg_columns_before.$preg_column_to_change.$preg_columns_after."\s*\\)\s*$/si"; + + // replace the column definiton in the CREATE TABLE statement + $newSQL = preg_replace($preg_pattern_change, '$1$2,$3$4$5$6)', $createtesttableSQL); + // remove comma at the beginning if the first column is changed + // probably somebody is able to put this into the first regex (using lookahead probably). + $newSQL = preg_replace("/^\s*(CREATE\s+TABLE\s+".preg_quote($this->quote($tmpname),"/")."\s+\(),\s*/",'$1',$newSQL); + if($debug) + { + $this->debugOutput .= "preg_column_to_change=(".$preg_column_to_change.")

"; + $this->debugOutput .= $createtesttableSQL."

"; + $this->debugOutput .= $newSQL."

"; + + $this->debugOutput .= $preg_pattern_change."

"; + } + if($newSQL!=$createtesttableSQL && $newSQL!="") // pattern did match, so PRIMARY KEY constraint removed :) + { + $createtesttableSQL = $newSQL; + if($debug) $this->debugOutput .= "
SUCCEEDED
"; + } + else + { + if($debug) $this->debugOutput .= "NO LUCK"; + // TODO: try removing table constraint + return false; + } + $createtesttableSQL = $newSQL; + } else + // TODO: Try removing table constraint + return false; + + break; + default: + if($debug) $this->debugOutput .= 'ERROR: unknown alter operation!

'; + $this->alterError = $errormsg . $lang['alter_unknown_operation']; + return false; + } + } + $droptempsql = 'DROP TABLE '.$this->quote_id($tmpname); + + $createnewtableSQL = "CREATE TABLE ".$this->quote($table_new)." ".preg_replace("/^\s*CREATE\s+TABLE\s+'?".str_replace("'","''",preg_quote($tmpname,"/"))."'?\s+(.*)$/is", '$1', $createtesttableSQL, 1); + + $newcolumns = ''; + $oldcolumns = ''; + reset($newcols); + while(list($key,$val) = each($newcols)) + { + $newcolumns .= ($newcolumns?', ':'').$this->quote_id($val); + $oldcolumns .= ($oldcolumns?', ':'').$this->quote_id($key); + } + $copytonewsql = 'INSERT INTO '.$this->quote_id($table_new).'('.$newcolumns.') SELECT '.$oldcolumns.' FROM '.$this->quote_id($tmpname); + } + } + $alter_transaction = 'BEGIN; '; + $alter_transaction .= $createtemptableSQL.'; '; //create temp table + $alter_transaction .= $copytotempsql.'; '; //copy to table + $alter_transaction .= $dropoldsql.'; '; //drop old table + $alter_transaction .= $createnewtableSQL.'; '; //recreate original table + $alter_transaction .= $copytonewsql.'; '; //copy back to original table + $alter_transaction .= $droptempsql.'; '; //drop temp table + + $preg_index="/^\s*(CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:".$this->sqlite_surroundings_preg("+",false," '\"\[`")."\s*)*ON\s+)(".$this->sqlite_surroundings_preg($table).")(\s*\((?:".$this->sqlite_surroundings_preg("+",false," '\"\[`")."\s*)*\)\s*)\s*$/i"; + foreach($recreateQueries as $recreate_query) + { + if($recreate_query['type']=='index') + { + // this is an index. We need to make sure the index is not on a column that we drop. If it is, we drop the index as well. + $indexInfos = $this->selectArray('PRAGMA index_info('.$this->quote_id($recreate_query['name']).')'); + foreach($indexInfos as $indexInfo) + { + if(!isset($newcols[$indexInfo['name']])) + { + if($debug) $this->debugOutput .= 'Not recreating the following index:

'.htmlencode($recreate_query['sql']).'

'; + // Index on a column that was dropped. Skip recreation. + continue 2; + } + } + } + // TODO: In case we renamed a column on which there is an index, we need to recreate the index with the column name adjusted. + + // recreate triggers / indexes + if($table == $table_new) + { + // we had no RENAME TO, so we can recreate indexes/triggers just like the original ones + $alter_transaction .= $recreate_query['sql'].';'; + } else + { + // we had a RENAME TO, so we need to exchange the table-name in the CREATE-SQL of triggers & indexes + switch ($recreate_query['type']) + { + case 'index': + $recreate_queryIndex = preg_replace($preg_index, '$1'.$this->quote_id(strtr($table_new, array('\\' => '\\\\', '$' => '\$'))).'$3 ', $recreate_query['sql']); + if($recreate_queryIndex!=$recreate_query['sql'] && $recreate_queryIndex != NULL) + $alter_transaction .= $recreate_queryIndex.';'; + else + { + // the CREATE INDEX regex did not match. this normally should not happen + if($debug) $this->debugOutput .= 'ERROR: CREATE INDEX regex did not match!?

'; + // just try to recreate the index originally (will fail most likely) + $alter_transaction .= $recreate_query['sql'].';'; + } + break; + + case 'trigger': + // TODO: IMPLEMENT + $alter_transaction .= $recreate_query['sql'].';'; + break; + default: + if($debug) $this->debugOutput .= 'ERROR: Unknown type '.htmlencode($recreate_query['type']).'

'; + $alter_transaction .= $recreate_query['sql'].';'; + } + } + } + $alter_transaction .= 'COMMIT;'; + if($debug) $this->debugOutput .= $alter_transaction; + return $this->multiQuery($alter_transaction); + } + } + + //multiple query execution + //returns true on success, false otherwise. Use getError() to fetch the error. + public function multiQuery($query) + { + if($this->type=="PDO") + $success = $this->db->exec($query); + else if($this->type=="SQLite3") + $success = $this->db->exec($query); + else + $success = $this->db->queryExec($query, $error); + return $success; + } + + + // checks whether a table has a primary key + public function hasPrimaryKey($table) + { + $table_info = $this->getTableInfo($table); + foreach($table_info as $row_id => $row_data) + { + if($row_data['pk']) + { + return true; + } + + } + return false; + } + + // Returns an array of columns by which rows can be uniquely adressed. + // For tables with a rowid column, this is always array('rowid') + // for tables without rowid, this is an array of the primary key columns. + public function getPrimaryKey($table) + { + $primary_key = array(); + // check if this table has a rowid + $getRowID = $this->select('SELECT ROWID FROM '.$this->quote_id($table).' LIMIT 0,1'); + if(isset($getRowID[0])) + // it has, so we prefer addressing rows by rowid + return array('rowid'); + else + { + // the table is without rowid, so use the primary key + $table_info = $this->getTableInfo($table); + if(is_array($table_info)) + { + foreach($table_info as $row_id => $row_data) + { + if($row_data['pk']) + $primary_key[] = $row_data['name']; + } + } + } + return $primary_key; + } + + // selects a row by a given key $pk, which is an array of values + // for the columns by which a row can be adressed (rowid or primary key) + public function wherePK($table, $pk) + { + $where = ""; + $primary_key = $this->getPrimaryKey($table); + foreach($primary_key as $pk_index => $column) + { + if($where!="") + $where .= " AND "; + $where .= $this->quote_id($column) . ' = '; + if(is_int($pk[$pk_index]) || is_float($pk[$pk_index])) + $where .= $pk[$pk_index]; + else + $where .= $this->quote($pk[$pk_index]); + } + return $where; + } + + //get number of rows in table + public function numRows($table, $dontTakeLong = false) + { + // as Count(*) can be slow on huge tables without PK, + // if $dontTakeLong is set and the size is > 2MB only count() if there is a PK + if(!$dontTakeLong || $this->getSize() <= 2000 || $this->hasPrimaryKey($table)) + { + $result = $this->select("SELECT Count(*) FROM ".$this->quote_id($table)); + return $result[0]; + } else + { + return '?'; + } + } + + //correctly escape a string to be injected into an SQL query + public function quote($value) + { + if($this->type=="PDO") + { + // PDO quote() escapes and adds quotes + return $this->db->quote($value); + } + else if($this->type=="SQLite3") + { + return "'".$this->db->escapeString($value)."'"; + } + else + { + return "'".sqlite_escape_string($value)."'"; + } + } + + //correctly escape an identifier (column / table / trigger / index name) to be injected into an SQL query + public function quote_id($value) + { + // double-quotes need to be escaped by doubling them + $value = str_replace('"','""',$value); + return '"'.$value.'"'; + } + + + //import sql + //returns true on success, error message otherwise + public function import_sql($query) + { + $import = $this->multiQuery($query); + if(!$import) + return $this->getError(); + else + return true; + } + + public function prepareQuery($query) + { + if($this->type=='PDO' || $this->type=='SQLite3') + return $this->db->prepare($query); + else + { + // here we are in trouble, SQLiteDatabase cannot prepare statements. + // we need to emulate prepare as best as we can + # todo: implement this + return null; + } + } + + public function bindValue($handle, $parameter, $value, $type) + { + if($this->type=='SQLite3') + { + $types = array( + 'bool'=>SQLITE3_INTEGER, + 'int'=>SQLITE3_INTEGER, + 'float'=>SQLITE3_FLOAT, + 'text'=>SQLITE3_TEXT, + 'blob'=>SQLITE3_BLOB, + 'null'=>SQLITE3_NULL); + if(!isset($types[$type])) + $type = 'text'; + // there is no SQLITE_BOOL, so check value and make sure it is 0/1 + if($type=='bool') + { + if($value===1 || $value===true) + $value=1; + elseif($value===0 || $value===false) + $value=0; + else + return false; + } + return $handle->bindValue($parameter, $value, $types[$type]); + } + if($this->type=='PDO') + { + $types = array( + 'bool'=>PDO::PARAM_BOOL, + 'int'=>PDO::PARAM_INT, + 'float'=>PDO::PARAM_STR, + 'text'=>PDO::PARAM_STR, + 'blob'=>PDO::PARAM_LOB, + 'null'=>PDO::PARAM_NULL); + if(!isset($types[$type])) + $type = 'text'; + // there is no PDO::PARAM_FLOAT, so we check it ourself + if($type=='float') + { + if(is_numeric($value)) + $value = (float) $value; + else + return false; + } + return $handle->bindValue($parameter, $value, $types[$type]); + } + else + # todo: workaround + return false; + + } + + public function executePrepared($handle, $fetchResult=false) + { + if($this->type=='PDO') + { + $ok=$handle->execute(); + if($fetchResult && $ok) + { + $res = $handle->fetchAll(); + $handle->closeCursor(); + return $res; + } + else + { + if($ok) + $handle->closeCursor(); + return $ok; + } + } + elseif($this->type=='SQLite3') + { + $resultset=$handle->execute(); + if($fetchResult && $resultset!==false) + { + $res = $resultset->fetchArray(); + $resultset->finalize(); + return $res; + } + else + { + if($resultset!==false) + $resultset->finalize(); + if($resultset===false) + return false; + else + return true; + } + } + else + { + #todo. + return false; + } + } + + //import csv + //returns true on success, error message otherwise + public function import_csv($filename, $table, $field_terminate, $field_enclosed, $field_escaped, $null, $fields_in_first_row) + { + @set_time_limit(-1); + $csv_handle = fopen($filename,'r'); + $csv_insert = "BEGIN;\n"; + $csv_number_of_rows = 0; + // PHP requires enclosure defined, but has no problem if it was not used + if($field_enclosed=="") $field_enclosed='"'; + // PHP requires escaper defined + if($field_escaped=="") $field_escaped='\\'; + // support tab delimiters + if($field_terminate=='\t') $field_terminate = "\t"; + while($csv_handle!==false && !feof($csv_handle)) + { + $csv_data = fgetcsv($csv_handle, 0, $field_terminate, $field_enclosed, $field_escaped); + if(is_array($csv_data) && ($csv_data[0] != NULL || count($csv_data)>1)) + { + $csv_number_of_rows++; + if($csv_number_of_rows==1) + { + if($this->getTypeOfTable($table)!="table") + { + // First,Create a new table + $csv_insert .="CREATE TABLE ".$this->quote($table)." ("; + $number_of_cols = count($csv_data); + foreach($csv_data as $csv_col => $csv_cell) + { + if($fields_in_first_row) + $csv_insert .= $this->quote($csv_cell); + else + $csv_insert.= $this->quote("col{$csv_col}"); + if($csv_col < $number_of_cols-1) + $csv_insert .= ", "; + } + $csv_insert .=");"; + + } else { + $number_of_cols = count($this->getTableInfo($table)); + } + if($fields_in_first_row) + continue; + } + $csv_insert .= "INSERT INTO ".$this->quote_id($table)." VALUES ("; + for($csv_col = 0; $csv_col < $number_of_cols; $csv_col++) + { + if(isset($csv_data[$csv_col])) + $csv_cell = $csv_data[$csv_col]; + else + $csv_cell = $null; + if($csv_cell == $null) + $csv_insert .= "NULL"; + else + $csv_insert.= $this->quote($csv_cell); + if($csv_col < $number_of_cols-1) + $csv_insert .= ","; + } + $csv_insert .= ");\n"; + + if($csv_number_of_rows % 5000 == 0) + { + $csv_insert .= "COMMIT;\nBEGIN;\n"; + } + } + } + if($csv_handle === false) + return "Error reading CSV file"; + else + { + $csv_insert .= "COMMIT;"; + fclose($csv_handle); + $import = $this->multiQuery($csv_insert); + if(!$import) + return $this->getError(); + else + return true; + } + } + + //export csv + public function export_csv($tables, $field_terminate, $field_enclosed, $field_escaped, $null, $crlf, $fields_in_first_row) + { + @set_time_limit(-1); + // we use \r\n if the _client_ OS is windows (as the exported file is downloaded to the client), \n otherwise + $crlf = (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'Win')!==false ? "\r\n" : "\n"); + + $query = "SELECT * FROM sqlite_master WHERE type='table' or type='view' ORDER BY type DESC"; + $result = $this->selectArray($query); + for($i=0; $igetTableInfo($result[$i]['tbl_name']); + $cols = array(); + for($z=0; $zquote_id($result[$i]['tbl_name']); + $table_result = $this->query($query); + $firstRow=true; + while($row = $this->fetch($table_result, "assoc")) + { + if(!$firstRow) + echo $crlf; + else + $firstRow=false; + + for($y=0; $ygetPath().$crlf; + echo "----".$crlf; + } + $query = "SELECT * FROM sqlite_master WHERE type='table' OR type='index' OR type='view' OR type='trigger' ORDER BY type='trigger', type='index', type='view', type='table'"; + $result = $this->selectArray($query); + + if($transaction) + echo "BEGIN TRANSACTION;".$crlf; + + //iterate through each table + for($i=0; $iquote_id($result[$i]['name']).";".$crlf; + } + if($structure) + { + if($comments) + { + echo "\r\n----".$crlf; + if($result[$i]['type']=="table" || $result[$i]['type']=="view") + echo "-- ".ucfirst($result[$i]['type'])." ".$lang['struct_for']." ".$result[$i]['tbl_name'].$crlf; + else // index or trigger + echo "-- ".$lang['struct_for']." ".$result[$i]['type']." ".$result[$i]['name']." ".$lang['on_tbl']." ".$result[$i]['tbl_name'].$crlf; + echo "----".$crlf; + } + echo $result[$i]['sql'].";".$crlf; + } + if($data && $result[$i]['type']=="table") + { + $query = "SELECT * FROM ".$this->quote_id($result[$i]['tbl_name']); + $table_result = $this->query($query, "assoc"); + + if($comments) + { + $numRows = $this->numRows($result[$i]['tbl_name']); + echo "\r\n----".$crlf; + echo "-- ".$lang['data_dump']." ".$result[$i]['tbl_name'].", ".sprintf($lang['total_rows'], $numRows).$crlf; + echo "----".$crlf; + } + $temp = $this->getTableInfo($result[$i]['tbl_name']); + $cols = array(); + $cols_quoted = array(); + for($z=0; $zquote_id($temp[$z][1]); + } + while($row = $this->fetch($table_result)) + { + $vals = array(); + for($y=0; $yquote($row[$cols[$y]]); + } + echo "INSERT INTO ".$this->quote_id($result[$i]['tbl_name'])." (".implode(",", $cols_quoted).") VALUES (".implode(",", $vals).");".$crlf; + } + } + } + } + if($transaction) + echo "COMMIT;".$crlf; + } +} +class GetParameters +{ + private $_fields; + + public function __construct(array $defaults = array()) + { + $this->_fields = $defaults; + } + + public function __set($key, $value) + { + $this->_fields[$key] = $value; + } + + public function __isset($key) + { + return isset($this->_fields[$key]); + } + + public function __unset($key) + { + unset($this->_fields[$key]); + } + + public function __get($key) + { + return $this->_fields[$key]; + } + + public function getURL(array $assoc = array(), $html = true, $prefix='?') + { + $arg_sep = ($html?'&':'&'); + return $prefix . http_build_query(array_merge($this->_fields, $assoc), '', $arg_sep); + } + + public function getLink(array $assoc = array(), $content = '[ link ]', $class = '', $title = '', $target='') + { + return '' . $content . ''; + } + + public function getForm(array $assoc = array(), $method = 'post', $upload = false, $name = '', $csrf = true) + { + $hidden = ''; + if($method == 'get') + { + $url = ''; + foreach(array_merge($this->_fields, $assoc) as $key => $value) + { + if(!is_null($value)) + $hidden .= ' '; + } + } + else + $url = $this->getURL($assoc); + + if($csrf && $method == 'post') + $hidden .= ''; + + return "
" . + $hidden; + } + + public function redirect(array $assoc = array(), $message="") + { + if($message!="") + { + $_SESSION[COOKIENAME.'messages'][md5($message)] = $message; + $url = $this->getURL(array_merge($assoc, array('message'=>md5($message))), false); + } + else + $url = $this->getURL($assoc, false); + + $protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http'); + + header("Location: ".$protocol."://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$url, true, 302); + exit; + } +}// class MicroTimer (issue #146) +// wraps calls to microtime(), calculating the elapsed time and rounding output +// +// class Resources (issue #157) +// outputs secondary files, such as css and javascript +// data is stored gzipped (gzencode) and encoded (base64_encode) +// +class Resources { + + // set this to the file containing getInternalResource; + // currently unused in split mode; set to __FILE__ for built PLA. + public static $embedding_file = __FILE__; + + private static $_resources = array( + 'css' => array( + 'mime' => 'text/css', + 'data' => 'resources/phpliteadmin.css', + ), + 'javascript' => array( + 'mime' => 'text/javascript', + 'data' => 'resources/phpliteadmin.js', + ), + 'favicon' => array( + 'mime' => 'image/x-icon', + 'data' => 'resources/favicon.ico', + 'base64' => 'true', + ), + ); + + // outputs the specified resource, if defined in this class. + // the main script should do no further output after calling this function. + public static function output($resource) + { + if (isset(self::$_resources[$resource])) { + $res =& self::$_resources[$resource]; + + if (function_exists('getInternalResource') && $data = getInternalResource($res['data'])) { + $filename = self::$embedding_file; + } else { + $filename = $res['data']; + } + + // use last-modified time as etag; etag must be quoted + $etag = '"' . filemtime($filename) . '"'; + + // check headers for matching etag; if etag hasn't changed, use the cached version + if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag) { + header('HTTP/1.0 304 Not Modified'); + return; + } + + header('Etag: ' . $etag); + + // cache file for at most 30 days + header('Cache-control: max-age=2592000'); + + // output resource + header('Content-type: ' . $res['mime']); + + if (isset($data)) { + if (isset($res['base64'])) { + echo base64_decode($data); + } else { + echo $data; + } + } else { + readfile($filename); + } + } + } + +} + + +// returns data from internal resources, available in single-file mode +function getInternalResource($res) { + $resources = array('resources/phpliteadmin.css'=>array(0=>0,1=>4059,),'resources/phpliteadmin.js'=>array(0=>4059,1=>4542,),'resources/favicon.ico'=>array(0=>8601,1=>1448,),); + + if (isset($resources[$res]) && $f = fopen(__FILE__, 'r')) { + fseek($f, __COMPILER_HALT_OFFSET__ + $resources[$res][0]); + $data = fread($f, $resources[$res][1]); + fclose($f); + return $data; + } + return false; +} + +// resources embedded below, do not edit! +__halt_compiler() ?>body{margin:0px;padding:0px;font-family:Arial,Helvetica,sans-serif;font-size:14px;color:#000;background-color:#e0ebf6;overflow:auto}.body_tbl td{padding:9px 2px 9px 9px}.left_td{width:100px}a{color:#03F;text-decoration:none;cursor:pointer}a:hover{color:#06F}hr{height:1px;border:0;color:#bbb;background-color:#bbb;width:100%}h1{margin:0px;padding:5px;font-size:24px;background-color:#f3cece;text-align:center;color:#000;border-top-left-radius:5px;border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px}#headerlinks{text-align:center;margin-bottom:10px;padding:5px 15px;border-color:#03F;border-width:1px;border-style:solid;border-left-style:none;border-right-style:none;font-size:12px;background-color:#e0ebf6;font-weight:bold}h1 #version{color:#000;font-size:16px}h1 #logo{color:#000}h2{margin:0px;padding:0px;font-size:14px;margin-bottom:20px}input,select,textarea,.CodeMirror{font-family:Arial,Helvetica,sans-serif;background-color:#eaeaea;color:#03F;border-color:#03F;border-style:solid;border-width:1px;margin:5px;border-radius:5px;-moz-border-radius:5px;padding:3px}input.btn{cursor:pointer}input.btn:hover{background-color:#ccc}fieldset label{min-width:200px;display:block;float:left}fieldset{padding:15px;border-color:#03F;border-width:1px;border-style:solid;border-radius:5px;-moz-border-radius:5px;background-color:#f9f9f9}#container{padding:10px}#leftNav{min-width:250px;padding:0px;border-color:#03F;border-width:1px;border-style:solid;background-color:#FFF;padding-bottom:15px;border-radius:5px;-moz-border-radius:5px}.databaseList select{max-width:200px}.viewTable tr td{padding:1px}#loginBox{width:500px;margin-left:auto;margin-right:auto;margin-top:50px;border-color:#03F;border-width:1px;border-style:solid;background-color:#FFF;border-radius:5px;-moz-border-radius:5px}#main{border-color:#03F;border-width:1px;border-style:solid;padding:15px;background-color:#FFF;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top-right-radius:5px;-moz-border-radius-bottomleft:5px;-moz-border-radius-bottomright:5px;-moz-border-radius-topright:5px}.td1{background-color:#f9e3e3;text-align:right;font-size:12px;padding-left:10px;padding-right:10px}.td2{background-color:#f3cece;text-align:right;font-size:12px;padding-left:10px;padding-right:10px}.tdheader{border-color:#03F;border-width:1px;border-style:solid;font-weight:bold;font-size:12px;padding-left:10px;padding-right:10px;background-color:#e0ebf6;border-radius:5px;-moz-border-radius:5px}.confirm{border-color:#03F;border-width:1px;border-style:dashed;padding:15px;background-color:#e0ebf6}.tab{display:block;padding:5px;padding-right:8px;padding-left:8px;border-color:#03F;border-width:1px;border-style:solid;margin-right:5px;float:left;border-bottom-style:none;position:relative;top:1px;padding-bottom:4px;background-color:#eaeaea;border-top-left-radius:5px;border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px}.tab_pressed{display:block;padding:5px;padding-right:8px;padding-left:8px;border-color:#03F;border-width:1px;border-style:solid;margin-right:5px;float:left;border-bottom-style:none;position:relative;top:1px;background-color:#FFF;cursor:default;border-top-left-radius:5px;border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px}.helpq{font-size:11px;font-weight:normal}#help_container{padding:0px;font-size:12px;margin-left:auto;margin-right:auto;background-color:#fff}.help_outer{background-color:#FFF;padding:0px;height:300px;position:relative}.help_list{padding:10px;height:auto}.headd{font-size:14px;font-weight:bold;display:block;padding:10px;background-color:#e0ebf6;border-color:#03F;border-width:1px;border-style:solid;border-left-style:none;border-right-style:none}.help_inner{padding:10px}.help_top{display:block;position:absolute;right:10px;bottom:10px}.warning,.delete,.empty,.drop,.delete_db{color:red}.sidebar_table{font-size:11px}.active_table,.active_db{text-decoration:underline}.null{color:#888}.found{background:#FF0;text-decoration:none} +function initAutoincrement() +{var i=0;while(document.getElementById('i'+i+'_autoincrement')!=undefined) +{document.getElementById('i'+i+'_autoincrement').disabled=true;i++;}} +function toggleAutoincrement(i) +{var type=document.getElementById('i'+i+'_type');var primarykey=document.getElementById('i'+i+'_primarykey');var autoincrement=document.getElementById('i'+i+'_autoincrement');if(!autoincrement)return false;if(type.value=='INTEGER'&&primarykey.checked) +autoincrement.disabled=false;else +{autoincrement.disabled=true;autoincrement.checked=false;}} +function toggleNull(i) +{var pk=document.getElementById('i'+i+'_primarykey');var notnull=document.getElementById('i'+i+'_notnull');if(pk.checked) +{notnull.disabled=true;notnull.checked=true;} +else +{notnull.disabled=false;}} +function checkAll(field) +{var i=0;while(document.getElementById('check_'+i)!=undefined) +{document.getElementById('check_'+i).checked=true;i++;}} +function uncheckAll(field) +{var i=0;while(document.getElementById('check_'+i)!=undefined) +{document.getElementById('check_'+i).checked=false;i++;}} +function changeIgnore(area,e,u) +{if(area.value!="") +{if(document.getElementById(e)!=undefined) +document.getElementById(e).checked=false;if(document.getElementById(u)!=undefined) +document.getElementById(u).checked=false;}} +function moveFields() +{var fields=document.getElementById("fieldcontainer");var selected=[];for(var i=0;i0){CodeMirror.commands.autocomplete(instance);}} +function checkFileSize(input) +{if(input.files&&input.files.length==1) +{if(input.files[0].size>fileUploadMaxSize) +{alert(fileUploadMaxSizeErrorMsg+": "+(fileUploadMaxSize/1024/1024)+" MiB");return false;}} +return true;}AAABAAEAEBAAAAEAIAAoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwoKZQAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEMDJMAAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASDg7BAAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAETDw9CCQkJ1QUFBb4AAABjAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgsLVgAAAO8YExP/AAAA7QAAALEAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQNDUsAAADJGBMT/xgTE/8AAAD/AAAAuAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZERE8DQoKwhgTE/8QDQ2sGBMT/xgTE/8AAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwICHkAAAD/EQwMzQAAAMIAAAD/AAAA7gAAAGEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOCwtWAAAA8RgTE/8IBQW1AAAA/wAAAP8AAADlAAAAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0KCsEAAAD/EQ8PzAAAAMkAAAD/AAAA/wAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDAAAA/xgTE/8TDw/FAAAA8gAAAP8AAADqAAAAJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAALUAAAD/GBMT/wAAALkAAAD/AAAA/wAAAIkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAAA4wAAAP8GBgbFAAAA2QAAAP8AAADGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF4AAAD5AAAA/RgTE/8AAAD/AAAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQAAAOIAAAD/AAAA/wAAAHYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjAAAArgAAAG4AAAAAAAAAAAAAAAAAAAAA \ No newline at end of file diff --git a/sk-klinik.my.id/public/phpliteadmin/phpliteadmin.config.php b/sk-klinik.my.id/public/phpliteadmin/phpliteadmin.config.php new file mode 100644 index 0000000..0c9384e --- /dev/null +++ b/sk-klinik.my.id/public/phpliteadmin/phpliteadmin.config.php @@ -0,0 +1,78 @@ + '/www/wwwroot/sk-klinik.my.id/database/database.sqlite', + 'name'=> 'Database 1' + ), +); + + +/* ---- Interface settings ---- */ + +// Theme! If you want to change theme, save the CSS file in same folder of phpliteadmin or in folder "themes" +$theme = 'phpliteadmin.css'; + +// the default language! If you want to change it, save the language file in same folder of phpliteadmin or in folder "languages" +// More about localizations (downloads, how to translate etc.): https://bitbucket.org/phpliteadmin/public/wiki/Localization +$language = 'en'; + +// set default number of rows. You need to relog after changing the number +$rowsNum = 30; + +// reduce string characters by a number bigger than 10 +$charsNum = 300; + +// maximum number of SQL queries to save in the history +$maxSavedQueries = 10; + +/* ---- Custom functions ---- */ + +//a list of custom functions that can be applied to columns in the databases +//make sure to define every function below if it is not a core PHP function +$custom_functions = array( + 'md5', 'sha1', 'time', 'strtotime', + // add the names of your custom functions to this array + /* 'leet_text', */ +); + +// define your custom functions here +/* +function leet_text($value) +{ + return strtr($value, 'eaAsSOl', '344zZ01'); +} +*/ + + +/* ---- Advanced options ---- */ + +//changing the following variable allows multiple phpLiteAdmin installs to work under the same domain. +$cookie_name = 'pla3412'; + +//whether or not to put the app in debug mode where errors are outputted +$debug = false; + +// the user is allowed to create databases with only these extensions +$allowed_extensions = array('db','db3','sqlite','sqlite3'); + diff --git a/sk-klinik.my.id/public/robots.txt b/sk-klinik.my.id/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/sk-klinik.my.id/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/sk-klinik.my.id/resources/css/app lama.css b/sk-klinik.my.id/resources/css/app lama.css new file mode 100644 index 0000000..5cd1e9b --- /dev/null +++ b/sk-klinik.my.id/resources/css/app lama.css @@ -0,0 +1,67 @@ +@import 'tailwindcss'; +@import '../../vendor/livewire/flux/dist/flux.css'; + +@source '../views'; +@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; +@source '../../vendor/livewire/flux-pro/stubs/**/*.blade.php'; +@source '../../vendor/livewire/flux/stubs/**/*.blade.php'; +@source "../../vendor/masmerise/livewire-toaster/resources/views/*.blade.php"; + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + + --color-zinc-50: #fafafa; + --color-zinc-100: #f5f5f5; + --color-zinc-200: #e5e5e5; + --color-zinc-300: #d4d4d4; + --color-zinc-400: #a3a3a3; + --color-zinc-500: #737373; + --color-zinc-600: #525252; + --color-zinc-700: #404040; + --color-zinc-800: #262626; + --color-zinc-900: #171717; + --color-zinc-950: #0a0a0a; + + --color-accent: var(--color-neutral-800); + --color-accent-content: var(--color-neutral-800); + --color-accent-foreground: var(--color-white); +} + +@layer theme { + .dark { + --color-accent: var(--color-white); + --color-accent-content: var(--color-white); + --color-accent-foreground: var(--color-neutral-800); + } +} + +@layer base { + + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentColor); + } +} + +[data-flux-field]:not(ui-radio, ui-checkbox) { + @apply gap-2 grid; +} + +[data-flux-label] { + @apply !mb-0 !leading-tight; +} + +input:focus[data-flux-control], +textarea:focus[data-flux-control], +select:focus[data-flux-control] { + @apply outline-hidden ring-2 ring-accent ring-offset-2 ring-offset-accent-foreground; +} + +/* \[:where(&)\]:size-4 { + @apply size-4; +} */ diff --git a/sk-klinik.my.id/resources/css/app.css b/sk-klinik.my.id/resources/css/app.css new file mode 100644 index 0000000..4d7e44e --- /dev/null +++ b/sk-klinik.my.id/resources/css/app.css @@ -0,0 +1,69 @@ +@import "tailwindcss"; +@import "../../vendor/livewire/flux/dist/flux.css"; + +@source '../views'; +@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; +@source '../../vendor/livewire/flux-pro/stubs/**/*.blade.php'; +@source '../../vendor/livewire/flux/stubs/**/*.blade.php'; +@source "../../vendor/masmerise/livewire-toaster/resources/views/*.blade.php"; + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + --font-sans: + "Instrument Sans", ui-sans-serif, system-ui, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + "Noto Color Emoji"; + + --color-zinc-50: var(--chosen-base-50); + --color-zinc-100: var(--chosen-base-100); + --color-zinc-200: var(--chosen-base-200); + --color-zinc-300: var(--chosen-base-300); + --color-zinc-400: var(--chosen-base-400); + --color-zinc-500: var(--chosen-base-500); + --color-zinc-600: var(--chosen-base-600); + --color-zinc-700: var(--chosen-base-700); + --color-zinc-800: var(--chosen-base-800); + --color-zinc-900: var(--chosen-base-900); + --color-zinc-950: var(--chosen-base-950); + + --color-accent: var(--chosen-accent-500); + --color-accent-content: var(--chosen-accent-600); + --color-accent-foreground: var(--color-white); +} + +@layer theme { + .dark { + --color-accent: var(--chosen-accent-400); + --color-accent-content: var(--chosen-accent-300); + --color-accent-foreground: var(--color-white); + } +} + +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentColor); + } +} + +[data-flux-field]:not(ui-radio, ui-checkbox) { + @apply gap-2 grid; +} + +[data-flux-label] { + @apply !mb-0 !leading-tight; +} + +input:focus[data-flux-control], +textarea:focus[data-flux-control], +select:focus[data-flux-control] { + @apply outline-hidden ring-2 ring-accent ring-offset-2 ring-offset-accent-foreground; +} + +/* \[:where(&)\]:size-4 { + @apply size-4; +} */ diff --git a/sk-klinik.my.id/resources/js/app.js b/sk-klinik.my.id/resources/js/app.js new file mode 100644 index 0000000..ca40ae6 --- /dev/null +++ b/sk-klinik.my.id/resources/js/app.js @@ -0,0 +1,23 @@ +import '../../vendor/masmerise/livewire-toaster/resources/js'; + +import Swal from 'sweetalert2'; +window.Swal = Swal; + +import { Html5Qrcode } from "html5-qrcode"; +window.Html5Qrcode = Html5Qrcode; + +import Trix from "trix"; +import "trix/dist/trix.css"; + +window.Trix = Trix; + +// Fungsi inisialisasi +const setupTrix = () => { + document.addEventListener("trix-file-accept", (e) => { + e.preventDefault(); + }); +}; + +// Jalankan saat load pertama kali dan setiap kali Livewire selesai navigasi +document.addEventListener("livewire:navigated", setupTrix); +setupTrix(); diff --git a/sk-klinik.my.id/resources/views/admin/patients/print.blade.php b/sk-klinik.my.id/resources/views/admin/patients/print.blade.php new file mode 100644 index 0000000..a022682 --- /dev/null +++ b/sk-klinik.my.id/resources/views/admin/patients/print.blade.php @@ -0,0 +1,126 @@ + + + + + + Kartu Pasien - {{ $patient->user->name }} + + + + + + +
+ +
+ + + +

+ Tips: Pastikan "Background Graphics" dicentang pada pengaturan print browser. +

+ + + diff --git a/sk-klinik.my.id/resources/views/admin/patients/verify-status.blade.php b/sk-klinik.my.id/resources/views/admin/patients/verify-status.blade.php new file mode 100644 index 0000000..5718c41 --- /dev/null +++ b/sk-klinik.my.id/resources/views/admin/patients/verify-status.blade.php @@ -0,0 +1,61 @@ + +
+ {{-- Card Utama --}} +
+ {{-- Header Status --}} +
+
+ + + +
+

Terverifikasi

+
+ + {{-- Data Pasien --}} +
+
+

Nama Pasien

+

+ {{ $patient->user->name }} +

+
+ +
+
+

NIK

+

+ {{ substr($patient->nik, 0, 10) }}****** +

+
+
+

Jenis Kelamin

+

+ {{ $patient->gender == 'L' ? 'Laki-laki' : 'Perempuan' }} +

+
+
+ +
+

Terdaftar Pada

+

+ {{ $patient->created_at->format('d F Y') }} +

+
+ + {{-- Info Box --}} +
+ +

+ Data ini ditarik secara realtime dari database sistem informasi {{ $site->name ?? 'Klinik' }}. +

+
+
+ + {{-- Footer Card --}} +
+

Verified Digital Document

+
+
+
+
diff --git a/sk-klinik.my.id/resources/views/components/action-message.blade.php b/sk-klinik.my.id/resources/views/components/action-message.blade.php new file mode 100644 index 0000000..d313ee6 --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/action-message.blade.php @@ -0,0 +1,14 @@ +@props([ + 'on', +]) + +
merge(['class' => 'text-sm']) }} +> + {{ $slot->isEmpty() ? __('Saved.') : $slot }} +
diff --git a/sk-klinik.my.id/resources/views/components/app-logo-icon.blade.php b/sk-klinik.my.id/resources/views/components/app-logo-icon.blade.php new file mode 100644 index 0000000..0adc3a2 --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/app-logo-icon.blade.php @@ -0,0 +1,8 @@ + + + diff --git a/sk-klinik.my.id/resources/views/components/app-logo.blade.php b/sk-klinik.my.id/resources/views/components/app-logo.blade.php new file mode 100644 index 0000000..3f66b71 --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/app-logo.blade.php @@ -0,0 +1,29 @@ +@props([ + 'sidebar' => false, +]) + +@if ($sidebar) + + + +@else + + + +@endif diff --git a/sk-klinik.my.id/resources/views/components/auth-header.blade.php b/sk-klinik.my.id/resources/views/components/auth-header.blade.php new file mode 100644 index 0000000..e596a3f --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/auth-header.blade.php @@ -0,0 +1,9 @@ +@props([ + 'title', + 'description', +]) + +
+ {{ $title }} + {{ $description }} +
diff --git a/sk-klinik.my.id/resources/views/components/auth-session-status.blade.php b/sk-klinik.my.id/resources/views/components/auth-session-status.blade.php new file mode 100644 index 0000000..98e0011 --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/auth-session-status.blade.php @@ -0,0 +1,9 @@ +@props([ + 'status', +]) + +@if ($status) +
merge(['class' => 'font-medium text-sm text-green-600']) }}> + {{ $status }} +
+@endif diff --git a/sk-klinik.my.id/resources/views/components/desktop-user-menu.blade.php b/sk-klinik.my.id/resources/views/components/desktop-user-menu.blade.php new file mode 100644 index 0000000..7fb3706 --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/desktop-user-menu.blade.php @@ -0,0 +1,39 @@ + + + + +
+ +
+ {{ auth()->user()->name }} + {{ auth()->user()->email }} +
+
+ + + + {{ __('Settings') }} + + + @csrf + + {{ __('Log out') }} + + + +
+
diff --git a/sk-klinik.my.id/resources/views/components/guest-layout.blade.php b/sk-klinik.my.id/resources/views/components/guest-layout.blade.php new file mode 100644 index 0000000..f40218b --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/guest-layout.blade.php @@ -0,0 +1,90 @@ + + + + + @include('partials.head') + {{-- Tambahkan script ini agar tidak ada 'flicker' putih saat refresh --}} + + + +{{-- Ganti bg-white menjadi bg-zinc-50 dark:bg-zinc-950 --}} + + + + {{-- Navbar Utama - Menyesuaikan Dark Mode --}} + +
+ + + + + + Beranda + + Profil + + + Layanan + + + Dokter + + + + Berita + + Kontak + + + + +
+ {{-- Toggle Dark/Light Mode --}} + + {{-- Ikon Matahari (Muncul saat Dark Mode) --}} + + + @auth + {{ __('Dashboard') }} + @else + {{ __('Masuk') }} + {{ __('Daftar') }} + @endauth +
+ + +
+
+ + {{-- Konten Halaman --}} +
+ {{ $slot }} +
+ + {{-- Footer --}} +
+
+ © {{ date('Y') }} Sistem Informasi {{ $site->name ?? 'Klinik Kami' }}. All rights reserved. +
+
+ + @fluxScripts + + + diff --git a/sk-klinik.my.id/resources/views/components/placeholder-pattern.blade.php b/sk-klinik.my.id/resources/views/components/placeholder-pattern.blade.php new file mode 100644 index 0000000..8a434f0 --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/placeholder-pattern.blade.php @@ -0,0 +1,12 @@ +@props([ + 'id' => uniqid(), +]) + + + + + + + + + diff --git a/sk-klinik.my.id/resources/views/components/settings/layout.blade.php b/sk-klinik.my.id/resources/views/components/settings/layout.blade.php new file mode 100644 index 0000000..3a65247 --- /dev/null +++ b/sk-klinik.my.id/resources/views/components/settings/layout.blade.php @@ -0,0 +1,20 @@ +
+
+ + {{ __('Profile') }} + {{ __('Security') }} + {{ __('Appearance') }} + +
+ + + +
+ {{ $heading ?? '' }} + {{ $subheading ?? '' }} + +
+ {{ $slot }} +
+
+
diff --git a/sk-klinik.my.id/resources/views/dashboard.blade.php b/sk-klinik.my.id/resources/views/dashboard.blade.php new file mode 100644 index 0000000..8f08c05 --- /dev/null +++ b/sk-klinik.my.id/resources/views/dashboard.blade.php @@ -0,0 +1,18 @@ + +
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
diff --git a/sk-klinik.my.id/resources/views/dashboard/admin.blade.php b/sk-klinik.my.id/resources/views/dashboard/admin.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/sk-klinik.my.id/resources/views/dashboard/pasien.blade.php b/sk-klinik.my.id/resources/views/dashboard/pasien.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/sk-klinik.my.id/resources/views/errors/maintenance.blade.php b/sk-klinik.my.id/resources/views/errors/maintenance.blade.php new file mode 100644 index 0000000..ecc2882 --- /dev/null +++ b/sk-klinik.my.id/resources/views/errors/maintenance.blade.php @@ -0,0 +1,71 @@ + + + + + @include('partials.head') + + + + +
+ + {{-- Icon Section --}} +
+
+ +
+
+ + {{-- Text Section --}} +
+ Mode Pemeliharaan Aktif + + Kami sedang melakukan pembaruan sistem untuk meningkatkan layanan di + {{ \App\Models\Setting::get('site_name') }}. + +
+ + + + {{-- Info Kontak Menggunakan Flux --}} +
+

Kontak Darurat

+ +
+ +
+

{{ \App\Models\Setting::get('clinic_phone') }}

+

Hubungi via WhatsApp / Telepon

+
+
+ +
+ +
+

Lokasi Klinik

+

+ {{ \App\Models\Setting::get('clinic_address') }} +

+
+
+
+ + {{-- Action --}} +
+ + Admin Login + +
+
+ +

+ © {{ date('Y') }} {{ \App\Models\Setting::get('site_name') }} +

+
+ + @fluxScripts + + + diff --git a/sk-klinik.my.id/resources/views/flux/icon/book-open-text.blade.php b/sk-klinik.my.id/resources/views/flux/icon/book-open-text.blade.php new file mode 100644 index 0000000..bff20a3 --- /dev/null +++ b/sk-klinik.my.id/resources/views/flux/icon/book-open-text.blade.php @@ -0,0 +1,47 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php + if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); + } + + $classes = Flux::classes('shrink-0')->add( + match ($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }, + ); + + $strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, + }; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + + + + diff --git a/sk-klinik.my.id/resources/views/flux/icon/chevrons-up-down.blade.php b/sk-klinik.my.id/resources/views/flux/icon/chevrons-up-down.blade.php new file mode 100644 index 0000000..bf1ba2b --- /dev/null +++ b/sk-klinik.my.id/resources/views/flux/icon/chevrons-up-down.blade.php @@ -0,0 +1,43 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php + if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); + } + + $classes = Flux::classes('shrink-0')->add( + match ($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }, + ); + + $strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, + }; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + diff --git a/sk-klinik.my.id/resources/views/flux/icon/folder-git-2.blade.php b/sk-klinik.my.id/resources/views/flux/icon/folder-git-2.blade.php new file mode 100644 index 0000000..292171b --- /dev/null +++ b/sk-klinik.my.id/resources/views/flux/icon/folder-git-2.blade.php @@ -0,0 +1,45 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php + if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); + } + + $classes = Flux::classes('shrink-0')->add( + match ($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }, + ); + + $strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, + }; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + + diff --git a/sk-klinik.my.id/resources/views/flux/icon/layout-grid.blade.php b/sk-klinik.my.id/resources/views/flux/icon/layout-grid.blade.php new file mode 100644 index 0000000..88c5698 --- /dev/null +++ b/sk-klinik.my.id/resources/views/flux/icon/layout-grid.blade.php @@ -0,0 +1,45 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php + if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); + } + + $classes = Flux::classes('shrink-0')->add( + match ($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }, + ); + + $strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, + }; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + + diff --git a/sk-klinik.my.id/resources/views/flux/navlist/group.blade.php b/sk-klinik.my.id/resources/views/flux/navlist/group.blade.php new file mode 100644 index 0000000..5e691a2 --- /dev/null +++ b/sk-klinik.my.id/resources/views/flux/navlist/group.blade.php @@ -0,0 +1,51 @@ +@props([ + 'expandable' => false, + 'expanded' => true, + 'heading' => null, +]) + + + +class('group/disclosure') }} + @if ($expanded === true) open @endif + data-flux-navlist-group +> + + + + + + + +
class('block space-y-[2px]') }}> +
+
{{ $heading }}
+
+ +
+ {{ $slot }} +
+
+ + + +
class('block space-y-[2px]') }}> + {{ $slot }} +
+ + diff --git a/sk-klinik.my.id/resources/views/layouts/app.blade.php b/sk-klinik.my.id/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..8c054bc --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/app.blade.php @@ -0,0 +1,6 @@ + + + {{ $slot }} + + + diff --git a/sk-klinik.my.id/resources/views/layouts/app/header.blade.php b/sk-klinik.my.id/resources/views/layouts/app/header.blade.php new file mode 100644 index 0000000..e963bdc --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/app/header.blade.php @@ -0,0 +1,78 @@ + + + + @include('partials.head') + + + + + + + + + + {{ __('Dashboard') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ __('Dashboard') }} + + + + + + + + + {{ __('Repository') }} + + + {{ __('Documentation') }} + + + + + {{ $slot }} + + @fluxScripts + + diff --git a/sk-klinik.my.id/resources/views/layouts/app/sidebar.blade.php b/sk-klinik.my.id/resources/views/layouts/app/sidebar.blade.php new file mode 100644 index 0000000..40e0123 --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/app/sidebar.blade.php @@ -0,0 +1,211 @@ + + + + + @include('partials.head') + + + + + + + + + + {{-- GROUP: PLATFORM --}} + + + {{-- Dashboard: Biasanya semua user (Admin/Patient) punya akses --}} + @can('view-dashboard') + + {{ __('Dashboard') }} + + @endcan + + {{-- MENU GUEST: Khusus user baru yang belum melengkapi data --}} + @hasrole('guest') + + {{ __('Profil Pengunjung') }} + + @endhasrole + + {{-- MENU PATIENT: Kita kembalikan ke @hasrole agar khusus untuk pasien saja --}} + @hasrole('patient') + + {{ __('Dashboard') }} + + + {{ __('Profil Saya') }} + + + + {{ __('Booking & Monitor Antrean') }} + + + + {{ __('Informasi') }} + + @endhasrole + + + + {{-- ===================== --}} + {{-- MANAJEMEN KLINIK (ADMIN/STAFF) --}} + {{-- ===================== --}} + {{-- Di sini kita pakai @can karena Admin & Staff bisa berbagi tugas --}} + @if (auth()->user()->canany(['doctor-manage', 'patient-manage', 'antrean-manage', 'service-manage'])) + + @can('doctor-manage') + + Kelola Dokter + + @endcan + + @can('patient-manage') + + Kelola Pasien + + @endcan + + @can('antrean-manage') + + Kelola Antrean + + @endcan + + @can('service-manage') + + Kelola Layanan + + @endcan + + @endif + + {{-- ===================== --}} + {{-- INFORMASI --}} + {{-- ===================== --}} + @if (auth()->user()->canany(['category-manage', 'news-manage'])) + + @can('category-manage') + + Kategori Berita + + @endcan + + @can('news-manage') + + Daftar Berita + + @endcan + + @endif + + {{-- ===================== --}} + {{-- MASTER DATA --}} + {{-- ===================== --}} + @if (auth()->user()->canany(['settings-manage', 'role-manage', 'user-manage'])) + + @can('settings-manage') + + Pengaturan Sistem + + @endcan + + @can('role-manage') + + Manajemen Role + + @endcan + + @can('user-manage') + + Manajemen Pengguna + + @endcan + + @endif + + + + + {{-- + + + {{ __('Repository') }} + + + + {{ __('Documentation') }} + + --}} + + + + + + + + + + + + + + +
+
+ + +
+ {{ auth()->user()->name }} + {{ auth()->user()->email }} +
+
+
+
+ + + + + + {{ __('Settings') }} + + + + + +
+ @csrf + + {{ __('Log out') }} + +
+
+
+
+ + {{ $slot }} + + + @fluxScripts + + + diff --git a/sk-klinik.my.id/resources/views/layouts/auth.blade.php b/sk-klinik.my.id/resources/views/layouts/auth.blade.php new file mode 100644 index 0000000..f9f7a70 --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/auth.blade.php @@ -0,0 +1,4 @@ + + {{ $slot }} + + diff --git a/sk-klinik.my.id/resources/views/layouts/auth/card.blade.php b/sk-klinik.my.id/resources/views/layouts/auth/card.blade.php new file mode 100644 index 0000000..313c990 --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/auth/card.blade.php @@ -0,0 +1,36 @@ + + + + + @include('partials.head') + + + + + @fluxScripts + + + + + diff --git a/sk-klinik.my.id/resources/views/layouts/auth/simple.blade.php b/sk-klinik.my.id/resources/views/layouts/auth/simple.blade.php new file mode 100644 index 0000000..997c964 --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/auth/simple.blade.php @@ -0,0 +1,32 @@ + + + + + @include('partials.head') + + + + + @fluxScripts + + + + + diff --git a/sk-klinik.my.id/resources/views/layouts/auth/split.blade.php b/sk-klinik.my.id/resources/views/layouts/auth/split.blade.php new file mode 100644 index 0000000..6a664ba --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/auth/split.blade.php @@ -0,0 +1,53 @@ + + + + + @include('partials.head') + + + +
+ + +
+ @fluxScripts + + + + + diff --git a/sk-klinik.my.id/resources/views/layouts/theme-style.blade.php b/sk-klinik.my.id/resources/views/layouts/theme-style.blade.php new file mode 100644 index 0000000..4efca48 --- /dev/null +++ b/sk-klinik.my.id/resources/views/layouts/theme-style.blade.php @@ -0,0 +1,8 @@ + diff --git a/sk-klinik.my.id/resources/views/livewire/admin/categories.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/categories.blade.php new file mode 100644 index 0000000..825c4dc --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/categories.blade.php @@ -0,0 +1,101 @@ +
+
+
+ Kategori Berita + Kelola kategori untuk mengelompokkan artikel kesehatan Anda. +
+ Tambah Kategori +
+ + {{-- Filter & Pencarian --}} +
+
+ +
+
+ + {{-- Tabel Kategori --}} + + + Nama Kategori + Slug (URL) + Jumlah Berita + Aksi + + + + @forelse ($categories as $cat) + + + {{ $cat->name }} + + + {{ $cat->slug }} + + + {{ $cat->news_count ?? 0 }} artikel + + +
+ + + +
+
+
+ @empty + + + Data kategori tidak ditemukan. + + + @endforelse +
+
+ +
+ {{ $categories->links() }} +
+ + {{-- Modal Input --}} + +
+
+ {{ $selected_id ? 'Ubah Kategori' : 'Kategori Baru' }} + Nama kategori akan digunakan sebagai filter artikel. +
+ + + +
+ Batal + Simpan Perubahan +
+ +
+
+ +@script + +@endscript diff --git a/sk-klinik.my.id/resources/views/livewire/admin/dashboard.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/dashboard.blade.php new file mode 100644 index 0000000..7cd194b --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/dashboard.blade.php @@ -0,0 +1,80 @@ +
+
+ Ikhtisar Dasbor + Selamat datang kembali, berikut ringkasan sistem hari ini. +
+ + {{-- Stats Grid --}} +
+ + Total Pasien + {{ $stats['total_patients'] }} + + + + Janji Temu Hari Ini + {{ $stats['today_appointments'] }} + + + + Total Dokter + {{ $stats['total_doctors'] }} + + + + Berita Dipublish + {{ $stats['published_news'] }} + +
+ +
+ {{-- Antrean Terbaru --}} +
+
+ Antrean Perlu Diproses + Lihat Semua +
+ + + + No. Antrean + Pasien + Layanan + Status + + + + @forelse($recentAppointments as $app) + + #{{ $app->queue_number }} + {{ $app->patient->name }} + {{ $app->serviceCategory->name }} + + {{ $app->status }} + + + @empty + + Tidak ada antrean hari ini. + + @endforelse + + +
+ + {{-- Berita Terpopuler --}} +
+ Berita Terpopuler +
+ @foreach($popularNews as $news) +
+
+

{{ $news->title }}

+

{{ $news->view_count }} views

+
+
+ @endforeach +
+
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/admin/doctor-manager.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/doctor-manager.blade.php new file mode 100644 index 0000000..791f103 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/doctor-manager.blade.php @@ -0,0 +1,227 @@ +
+ + {{-- Header --}} +
+
+ Manajemen Dokter + Kelola data dokter dan jadwal praktik. +
+ + Tambah Dokter + +
+ + {{-- Filter --}} +
+ +
+ +
+ +
+ + + @foreach ($specializations as $sp) + + @endforeach + +
+ +
+ + {{-- Table --}} + + + + Foto + Nama + Spesialis + Telepon + Email + Jadwal + Aksi + + + + @forelse ($doctors as $doctor) + + + {{-- FOTO --}} + + + + + {{ $doctor->name }} + + + + {{ $doctor->specialization }} + + + + {{ $doctor->phone }} + {{ $doctor->email }} + + @php + $activeDays = collect($doctor->schedule)->filter(fn($time) => !empty($time)); + @endphp + + @if ($activeDays->count() > 0) + + + {{ $activeDays->count() }} Hari + + + +
+

Jam Praktik

+ @foreach ($doctor->schedule as $day => $time) + @if ($time) +
+ {{ $day }} + {{ $time }} +
+ @endif + @endforeach +
+
+
+ @else + Belum diatur + @endif +
+ + +
+ + + + + +
+
+ +
+ @empty + + +
+ + + Tidak ada dokter ditemukan. + +
+
+
+ @endforelse +
+ +
+ + {{-- Pagination --}} +
+ +
+ + {{-- Modal --}} + + +
+ + + {{ $doctorId ? 'Edit Dokter' : 'Dokter Baru' }} + + + {{-- Nama --}} + + + {{-- Spesialis --}} + + + {{-- Telepon --}} + + + {{-- Email --}} + + + {{-- Jadwal --}} +
+ Jadwal Praktik (Jam Kerja) +
+ @foreach (['Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu', 'Minggu'] as $day) +
+ {{ $day }} + +
+ @endforeach +
+ Kosongkan jika tidak ada praktik di hari tersebut. +
+ + {{-- FOTO UPLOAD --}} +
+ + + + + {{-- Loading --}} +
+ Uploading... +
+ + {{-- Preview foto baru --}} + @if ($photo) + + @endif + + {{-- Foto lama --}} + @if (!$photo && $oldPhoto) + + @endif +
+ + {{-- Tombol --}} +
+ + Batal + + + + Simpan Dokter + +
+ + + +
+ +
+ +{{-- SweetAlert --}} +@script + +@endscript diff --git a/sk-klinik.my.id/resources/views/livewire/admin/manage-antrean.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/manage-antrean.blade.php new file mode 100644 index 0000000..4248ec6 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/manage-antrean.blade.php @@ -0,0 +1,695 @@ +
+ {{-- CSS Khusus untuk Print --}} + + + {{-- Header Section --}} +
+
+ Kelola Antrean + + + + {{ \Carbon\Carbon::parse($search_date)->translatedFormat('l, d F Y') }} + + +
+ +
+ + Pasien Baru (Walk-in) + + + Panggil Selanjutnya + +
+
+ + {{-- Panel Kontrol & Filter --}} +
+ {{-- Grup 1: Filter Poli/Dokter --}} +
+ Filter Poli + / Dokter + {{-- Hapus variant="listbox" karena itu fitur Pro --}} + + + @foreach ($doctors as $doc) + + @endforeach + +
+ + {{-- Grup 2: Panggil Manual --}} +
+ Panggil + Nomor Manual +
+ + Panggil + +
+
+ + {{-- Grup 3: Filter Tanggal --}} +
+ Ganti + Tanggal Data + +
+
+ + {{-- 1. HERO SECTION: SEKARANG DIPANGGIL --}} +
+ @if ($currentCalling) +
+
+
+
+ + + + + Sedang Dipanggil + + @if ($currentCalling->doctor) + + {{ $currentCalling->doctor->name }} + + @endif +
+ +

+ {{ $currentCalling->patient->name }} +

+ +
+ + {{ $currentCalling->serviceCategory->name ?? 'Ruang Pemeriksaan' }} +
+ +
+ + PANGGIL ULANG + + + SELESAIKAN PEMERIKSAAN + +
+
+ + {{-- Box Nomor Antrean Besar --}} +
+ No. Antrean + + {{ str_pad($currentCalling->queue_number, 2, '0', STR_PAD_LEFT) }} + +
+
+
+ @else +
+
+ +
+ Belum Ada Pasien Yang Dipanggil + Silakan klik "Panggil Selanjutnya" atau pilih pasien di tabel bawah. +
+ @endif +
+ + {{-- 2. STATS SECTION --}} +
+ +
+ +
+
+

Total Antrean

+

{{ $stats['total'] }}

+
+
+ + +
+ +
+
+

Menunggu

+

{{ $stats['waiting'] }}

+
+
+ + +
+ +
+
+

Selesai

+

{{ $stats['finished'] }} +

+
+
+
+ + {{-- 3. TABLE SECTION DENGAN TAB --}} + +
+
+ + + + + + + + +
+
+ Menampilkan antrean pada hari terpilih +
+
+ + + + No + Pasien + + + Status + Aksi + + + + @forelse ($appointments as $app) + + + + {{ str_pad($app->queue_number, 2, '0', STR_PAD_LEFT) }} + + + + +
+ {{ $app->patient->name }}
+
+ + {{ $app->created_at->format('H:i') }} WIB +
+
+ + + + + + + @php + $statusInfo = match ($app->status) { + 'waiting' => ['color' => 'yellow', 'label' => 'MENUNGGU'], + 'calling' => ['color' => 'orange', 'label' => 'DIPANGGIL'], + 'skipped' => ['color' => 'red', 'label' => 'TERLAMBAT'], + 'finished' => ['color' => 'green', 'label' => 'SELESAI'], + 'cancelled' => ['color' => 'zinc', 'label' => 'BATAL'], + default => ['color' => 'zinc', 'label' => strtoupper($app->status)], + }; + @endphp + + {{ $statusInfo['label'] }} + + + + +
+ @if ($app->status == 'waiting' || $app->status == 'skipped') + + @endif + + @if ($app->status == 'calling') + + + @endif + + + + + Lihat / Cetak Tiket + Kembalikan ke Status Tunggu + + Lewati (Panggil Berikutnya) + + Batalkan Antrean + + +
+
+
+ @empty + + + Tidak ada data antrean pada kategori ini. + + + @endforelse +
+
+ +
+ {{ $appointments->links() }} +
+
+ + {{-- MODAL TIKET DIGITAL --}} + + @if ($selectedAppointment) +
{{-- Pembungkus Tambahan --}} +
+ {{-- Bagian Header Tiket --}} +
+
ANTREAN
+

{{ $site->name }}

+
+ +
+ Nomor Antrean +
+ {{ str_pad($selectedAppointment->queue_number, 2, '0', STR_PAD_LEFT) }} +
+
+ {{ $selectedAppointment->serviceCategory->name ?? 'UMUM' }} +
+
+ +
+
+ Pasien: + {{ $selectedAppointment->patient->name }} +
+
+ Poli: + {{ $selectedAppointment->doctor->name ?? '-' }} +
+
+
+
+ + {{-- Footer Modal (Akan otomatis hilang karena CSS print di atas) --}} +
+ Tutup + + + Cetak Tiket + +
+ @endif +
+ + {{-- MODAL WALK-IN (Pendaftaran Baru) --}} + +
+
+ Pendaftaran Pasien Walk-in + Daftarkan pasien yang datang langsung tanpa janji temu sebelumnya. +
+ +
+ {{-- Pilih Pasien --}} +
+ Cari & Pilih Pasien + + {{-- Input untuk mengetik nama/NIK --}} + + + {{-- Dropdown yang isinya terfilter otomatis --}} + + + @foreach ($patients as $user) + + @endforeach + + + @if ($search_patient_name) +
+ Menampilkan hasil pencarian untuk: "{{ $search_patient_name }}" +
+ @endif + + @error('walkin_patient_id') + {{ $message }} + @enderror +
+ +
+ {{-- Pilih Dokter --}} + + Pilih Dokter + @foreach ($doctors as $doc) + {{ $doc->name }} + @endforeach + + + {{-- Pilih Poli --}} + + Pilih Layanan + @foreach ($services as $service) + {{ $service->name }} + @endforeach + +
+ + +
+ +
+ + Batalkan + Daftarkan & Cetak + Antrean +
+
+
+ + {{-- MODAL REKAM MEDIS (FORM PEMERIKSAAN DOKTER) --}} + +
+
+ Input Rekam Medis Pasien + Masukkan catatan klinis dan diagnosa sebelum menyelesaikan pemeriksaan. +
+ + @if ($currentExamining) +
+ {{-- Ringkasan Pendaftaran Pasien --}} +
+
Nama Pasien: {{ $currentExamining->patient->name }}
+
Poli / Dokter: {{ $currentExamining->serviceCategory->name ?? '-' }} / {{ $currentExamining->doctor->name ?? '-' }}
+
Keluhan Awal Pendaftaran: "{{ $currentExamining->notes ?? 'Tidak ada' }}"
+
+ + {{-- Inputs Rekam Medis --}} + + + + + + + +
+ @endif + +
+ Kembali + Simpan & Selesaikan Pemeriksaan +
+
+
+ + @script + + @endscript +
diff --git a/sk-klinik.my.id/resources/views/livewire/admin/news/news-create.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/news/news-create.blade.php new file mode 100644 index 0000000..bf8c012 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/news/news-create.blade.php @@ -0,0 +1,66 @@ +
+ {{-- Header: Identik dengan RoleManager --}} +
+
+ Tulis Berita + Buat artikel edukasi kesehatan untuk pasien Anda. +
+ Kembali +
+ + +
+ {{-- Input Judul --}} + + +
+ {{-- Dropdown Kategori --}} +
+ + @foreach ($categories as $cat) + {{ $cat->name }} + @endforeach + + +
+ + {{-- Input Gambar --}} +
+ + +
+
+ + {{-- Preview Gambar jika sudah dipilih --}} + @if ($image) +
+ +
+
+ @endif + + {{-- Isi Berita --}} +
+ Konten Berita + +
+ + +
+ + +
+ +
+ + + Simpan Berita +
+ +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/admin/news/news-edit.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/news/news-edit.blade.php new file mode 100644 index 0000000..4a6a339 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/news/news-edit.blade.php @@ -0,0 +1,79 @@ +
+
+
+ Edit Berita + Perbarui informasi atau edukasi kesehatan yang sudah ada. +
+ Kembali +
+ + +
+ {{-- Input Judul --}} + + +
+ {{-- Dropdown Kategori --}} +
+ + @foreach ($categories as $cat) + {{ $cat->name }} + @endforeach + + +
+ + {{-- Input Gambar --}} +
+ + +
+
+ + {{-- Preview Area --}} +
+ @if ($oldImage && !$image) +
+

Gambar Saat Ini:

+ +
+ @endif + + @if ($image) +
+

Preview Gambar Baru:

+ +
+ @endif +
+ + {{-- Isi Berita (Trix Editor) --}} +
+ Konten Berita + +
+ + +
+ +
+ + {{-- Footer Form: Checkbox & Submit --}} +
+ {{-- Gunakan boolean value agar tercentang otomatis --}} + + + Perbarui Berita +
+ +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/admin/news/news.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/news/news.blade.php new file mode 100644 index 0000000..a8b9fe1 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/news/news.blade.php @@ -0,0 +1,113 @@ +
+
+
+ Manajemen Berita + Tulis edukasi kesehatan atau informasi terbaru untuk pasien. +
+ {{-- Menggunakan route create yang akan kita buat dibawah --}} + + Tambah Berita + +
+ + {{-- Filter & Pencarian --}} +
+
+ +
+
+ + {{-- Tabel Berita --}} + + + Berita + Kategori + Status + Dilihat + Tanggal + Aksi + + + + @forelse ($news as $item) + + +
+ @if($item->image) + + @else +
+ +
+ @endif +
+ + {{ $item->title }} + + {{ $item->slug }} +
+
+
+ + + {{ $item->category->name ?? 'Uncategorized' }} + + + + + + + {{ $item->view_count }}x + + {{ $item->created_at->translatedFormat('d F Y') }} + + +
+ + + +
+
+
+ @empty + + + Data berita tidak ditemukan. + + + @endforelse +
+
+ +
+ +
+
+ +@script + +@endscript diff --git a/sk-klinik.my.id/resources/views/livewire/admin/patient-history.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/patient-history.blade.php new file mode 100644 index 0000000..1b580e0 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/patient-history.blade.php @@ -0,0 +1,99 @@ +
+ +
+
+ ← + Kembali ke Daftar Pasien +

+ Riwayat Medis: {{ $patient->user->name ?? 'Pasien' }} +

+
+ No. RM: {{ $patient->medical_record_number ?? '-' }} + + NIK: {{ $patient->nik }} + + Telepon: {{ $patient->phone }} +
+
+
+ + +
+

+ Lini Masa Riwayat Berobat & Keluhan +

+ + @if ($medicalRecords->count() > 0) +
+ @foreach ($medicalRecords as $record) +
+ + + + + +
+
+
+ + {{ $record->created_at->translatedFormat('d F Y') }} + +

+ Layanan: {{ $record->appointment->serviceCategory->name ?? '-' }} | + Dokter: {{ $record->doctor->name ?? 'Belum Ditentukan' }} +

+
+
+ + +
+
+

Keluhan / + Anamnesis:

+

"{{ $record->symptoms }}" +

+
+ +
+

Diagnosa + Dokter:

+

+ {{ $record->diagnosis }}

+
+ + @if ($record->treatment) +
+

Tindakan + / Resep Obat:

+

{{ $record->treatment }} +

+
+ @endif + + @if ($record->notes) +
+

Catatan + Tambahan:

+

{{ $record->notes }}

+
+ @endif +
+
+
+ @endforeach +
+ + +
+ {{ $medicalRecords->links() }} +
+ @else +
+ Belum ada riwayat rekam medis (pemeriksaan dokter) untuk pasien ini. +
+ @endif +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/admin/patient-manager.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/patient-manager.blade.php new file mode 100644 index 0000000..02dfbac --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/patient-manager.blade.php @@ -0,0 +1,384 @@ +
+
+
+ Database Pasien + Daftar seluruh pasien yang telah melengkapi profil medis. +
+ Tambah Pasien +
+ +
+ {{-- Filter Area --}} +
+
+
+ +
+ Scan Kartu +
+ +
+ + + + + + +
+
+ + {{-- Table --}} + + + Pasien + No. RM + NIK + Kontak + Penjamin + Aksi + + + + @forelse ($patients as $patient) + + +
+ +
+
{{ $patient->user->name }} +
+
+ {{ $patient->gender == 'L' ? 'Laki-laki' : 'Perempuan' }}
+
+
+
+ + {{ $patient->medical_record_number }} + + {{ $patient->nik }} + + +
{{ $patient->phone }}
+
{{ $patient->address }}
+
+ + + + {{ $patient->insurance_type }} + + + + +
+ + Lihat Riwayat + + + + +
+
+
+ @empty + + +
Tidak ada data pasien.
+
+
+ @endforelse +
+
+ +
{{ $patients->links() }}
+
+ + {{-- MODAL DETAIL --}} + + @if ($selectedPatient) +
+
+ +
+ {{ $selectedPatient->user->name }} +
+ {{ $selectedPatient->nik }} + + {{ $selectedPatient->gender === 'L' ? 'Laki-laki' : 'Perempuan' }} + +
+
+
+
+
+
+
+

Gol. Darah

+ {{ $selectedPatient->blood_type ?? '-' }} + +
+
+

Tgl Lahir

+

+ {{ \Carbon\Carbon::parse($selectedPatient->date_of_birth)->format('d/m/Y') }}

+
+
+

Penjamin

+ {{ $selectedPatient->insurance_type }} +
+
+
+

Alamat

+

+ {{ $selectedPatient->address }} +

+
+
+
+ + Tutup + + {{-- Tombol Cetak diarahkan ke route cetak yang kamu miliki --}} + + Cetak Kartu + +
+ @endif +
+ + {{-- MODAL EDIT --}} + +
+ Edit Profil Pasien Lengkap + Pastikan informasi medis dan kontak darurat sudah sesuai. +
+ +
+ {{-- Section 1: Identitas Dasar --}} +
+ + + + + + + + + + +
+ +
+ + {{-- Section 2: Kontak & Alamat --}} +
+ + + + + + + + + +
+ +
+

Kontak Darurat

+
+ + + +
+
+ + {{-- Section 3: Asuransi --}} +
+ + + + + + +
+ +
+ + Batal + + Simpan Perubahan Data +
+
+
+ + {{-- MODAL TAMBAH PASIEN --}} + +
+ Registrasi Pasien Baru + Input data medis lengkap untuk pendaftaran pasien baru. +
+ +
+ {{-- Seksi 1: Akun & Identitas Dasar --}} +
+ Akun & Identitas + Dasar + + +
+ + + + + +
+ + + + + + + + + + + + + +
+
+ +
+ + +
+
+ + {{-- Seksi 2: Kontak --}} +
+ Informasi Kontak + + + + + +
+ + {{-- Seksi 3: Kontak Darurat --}} +
+ Kontak + Darurat + +
+ + + +
+
+ + {{-- Seksi 4: Penjamin --}} +
+ Metode Pembayaran / + Penjamin + + +
+ + + + + + +
+ +
+
+
+ +
+ + Batal + + + Daftarkan Pasien + +
+
+
+ + {{-- MODAL SCANNER --}} + + Scan Kartu +
+ + Batal + +
+
+ +@script + +@endscript diff --git a/sk-klinik.my.id/resources/views/livewire/admin/permission-manager.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/permission-manager.blade.php new file mode 100644 index 0000000..94ea613 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/permission-manager.blade.php @@ -0,0 +1,98 @@ +
+
+
+ Master Permission + Daftar seluruh hak akses yang tersedia di dalam sistem. +
+
+ Kembali ke Role + Tambah Permission +
+
+ + {{-- Filter & Pencarian --}} +
+
+ +
+
+ + {{-- Tabel Permissions --}} + + + Nama Permission + Guard + Dibuat Pada + Aksi + + + + @forelse ($permissions as $permission) + + + {{ $permission->name }} + + + {{ $permission->guard_name }} + + {{ $permission->created_at->translatedFormat('d F Y') }} + +
+ + +
+
+
+ @empty + + + Data permission tidak ditemukan. + + + @endforelse +
+
+ +
+ +
+ + {{-- Modal Input --}} + +
+
+ {{ $permissionId ? 'Ubah Permission' : 'Permission Baru' }} + Gunakan format kebab-case (contoh: user-create, edit-post). +
+ + + +
+ Batal + Simpan +
+ +
+
+ +@script + +@endscript diff --git a/sk-klinik.my.id/resources/views/livewire/admin/role-manager.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/role-manager.blade.php new file mode 100644 index 0000000..b8b2409 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/role-manager.blade.php @@ -0,0 +1,111 @@ +
+
+
+ Manajemen Role + Atur hak akses pengguna sistem Anda di sini. +
+
+ + Kelola Master Permission + + + Tambah Role +
+
+ + {{-- Filter & Pencarian --}} +
+
+ +
+
+ + {{-- Tabel Roles --}} + + + Nama Role + Guard + Dibuat Pada + Aksi + + + + @forelse ($roles as $role) + + + {{ $role->name }} + + + {{ $role->guard_name }} + + {{ $role->created_at->translatedFormat('d F Y') }} + +
+ + + + @if (!in_array(strtolower($role->name), ['admin', 'super-admin'])) + + @endif +
+
+
+ @empty + + + Data role tidak ditemukan. + + + @endforelse +
+
+ +
+ +
+ + {{-- Modal Input --}} + +
+
+ {{ $roleId ? 'Ubah Role' : 'Role Baru' }} + Pastikan nama role bersifat unik. +
+ + + +
+ Batal + Simpan Perubahan +
+ +
+
+ +@script + +@endscript diff --git a/sk-klinik.my.id/resources/views/livewire/admin/role-permissions.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/role-permissions.blade.php new file mode 100644 index 0000000..ecd7053 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/role-permissions.blade.php @@ -0,0 +1,45 @@ +
+
+ Atur Hak Akses: {{ $role->name }} + Aktifkan atau nonaktifkan hak akses untuk role ini. +
+ +
+
+ @foreach($allPermissions as $group => $permissions) +
+ {{-- Header Grup --}} +
+ + + {{ $group }} + +
+ + {{-- List Permission dengan Switch --}} +
+ @foreach($permissions as $permission) +
+ + {{ $permission->name }} + + + {{-- Menggunakan Flux Switch --}} + +
+ @endforeach +
+
+ @endforeach +
+ +
+ Simpan Perubahan + Kembali +
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/admin/service-manager.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/service-manager.blade.php new file mode 100644 index 0000000..b0707b3 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/service-manager.blade.php @@ -0,0 +1,192 @@ +
+ + {{-- HEADER --}} +
+
+ Manajemen Layanan + Kelola daftar layanan dan galeri foto klinik. +
+ + + Tambah Layanan + +
+ + {{-- FILTER --}} +
+
+ +
+ +
+ + + @foreach ($categories as $id => $name) + + @endforeach + +
+
+ + {{-- TABLE --}} + + + Foto + Nama Layanan + Kategori + Deskripsi + Aksi + + + + @forelse ($services as $s) + + {{-- Avatar Stack untuk Foto --}} + +
+ @if ($s->photo && count($s->photo) > 0) + @foreach (array_slice($s->photo, 0, 3) as $img) + + @endforeach + @if (count($s->photo) > 3) +
+ +{{ count($s->photo) - 3 }} +
+ @endif + @else +
+ +
+ @endif +
+
+ + {{ $s->name }} + + + {{ $s->category->name }} + + + +

+ {{ Str::limit(strip_tags($s->description), 50, '...') }} +

+
+ + +
+ + +
+
+
+ @empty + + + Tidak ada data layanan ditemukan. + + + @endforelse +
+
+ +
+ {{ $services->links() }} +
+ + {{-- MODAL FORM --}} + +
+ {{ $serviceId ? 'Edit' : 'Tambah' }} Layanan + Isi informasi detail mengenai layanan klinik di bawah ini. +
+ +
+
+ + + + + @foreach ($categories as $id => $name) + + @endforeach + +
+ +
+ Deskripsi Detail + + + + @error('description') +

{{ $message }}

+ @enderror +
+ + {{-- MULTIPLE PHOTO UPLOAD --}} +
+ Foto & Galeri (Multiple) + + + +
+ Sedang mengunggah foto... +
+ + {{-- Preview Foto yang Sudah Ada --}} + @if ($existingPhotos) +
+ @foreach ($existingPhotos as $index => $path) +
+ + +
+ @endforeach +
+ @endif + + {{-- Preview Foto Baru (Temporary) --}} + @if ($photos) +
+ @foreach ($photos as $photo) +
+ +
+ Baru +
+
+ @endforeach +
+ @endif +
+ +
+ + Batal + + + + Simpan Perubahan + Memproses... + +
+
+
+ +
diff --git a/sk-klinik.my.id/resources/views/livewire/admin/site-settings.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/site-settings.blade.php new file mode 100644 index 0000000..c559560 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/site-settings.blade.php @@ -0,0 +1,289 @@ +
+
+ Pengaturan Sistem + Konfigurasi identitas klinik, profil dinamis, daftar tim medis, dan tampilan visual dashboard. +
+ + {{-- Navigasi Tab --}} +
+ + + + + + +
+ +
+ {{-- Tab 1: General & SEO --}} +
+ +
+ + + + +
+ + Logo Utama +
+ @if ($logo) + + @elseif ($existing_logo) + + @endif + +
+
+ + + Favicon +
+ @if ($favicon) + + @elseif ($existing_favicon) + + @endif + +
+
+
+
+
+
+ + {{-- Tab 2: Profil & Tim Klinik --}} +
+ {{-- Section 1: Hero & Deskripsi --}} + + 1. Banner Hero & Pembuka Landing Page + + + + + + {{-- Section 2: Legalitas --}} + + 2. Legalitas Instansi + +
+ + + + +
+
+ + {{-- Section 3: Visi Misi --}} + + 3. Visi & Misi Klinik + + + +
+ Misi Klinik (Gunakan Fitur Bullet List di Editor) + + +
+
+ + {{-- Section 4: Tim Klinik --}} + +
+ 4. Manajemen Anggota & Tim Medis + Gunakan fitur list/bullet poin untuk mendata nama staf secara dinamis. +
+ + +
+
+ Daftar Dokter + + +
+ +
+ Daftar Perawat + + +
+ +
+ Daftar Bidan + + +
+ +
+ Daftar Tim Farmasi + + +
+
+ +
+ Daftar Tim Pendukung (Admin, CS, Driver, Satpam) + + +
+
+
+ + {{-- Tab 3: Contact Info --}} +
+ +
+ + + +
+ +
+ +
+
+ +

Contoh: -7.593714

+
+
+ +

Contoh: 111.859664

+
+ +
+ + Buka Google Maps untuk cari koordinat + +
+
+
+
+
+ + {{-- Tab 4: Status Operasional --}} +
+ +
+
+ Kontrol Operasional + Atur ketersediaan layanan sistem untuk publik. +
+ + + +
+ +
+ Pendaftaran Pasien Baru + Izinkan pengunjung mendaftar akun melalui Landing Page. +
+ +
+ + +
+ Mode Pemeliharaan (Maintenance) + Aktifkan jika sistem sedang dalam perbaikan besar. +
+ +
+
+ + @if ($maintenance_mode) +
+ + + Perhatian: Saat Mode Pemeliharaan aktif, pengunjung umum mungkin tidak dapat mengakses fitur utama klinik. + +
+ @endif +
+
+
+ + {{-- Tab 5: Branding & Colors --}} +
+ +
+
+ Warna Aksen Tema + Digunakan pada tombol, link, dan elemen aktif. + + + @foreach (['teal', 'emerald', 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose', 'red', 'orange', 'amber', 'yellow', 'lime'] as $color) + +
+
+ {{ $color }} +
+
+ @endforeach +
+
+ + + +
+ Nuansa Dasar (Background) + Pilih nuansa abu-abu yang paling nyaman. + + + @foreach (['slate', 'gray', 'zinc', 'neutral', 'stone'] as $gray) + +
+ {{ $gray }} + +
+ @endforeach +
+
+
+
+
+ + {{-- Tab 6: Social Media --}} +
+ +
+ + + +
+
+
+ + {{-- Tombol Submit Tunggal --}} +
+ Simpan Seluruh Pengaturan Klinik +
+
+
\ No newline at end of file diff --git a/sk-klinik.my.id/resources/views/livewire/admin/user-manager.blade.php b/sk-klinik.my.id/resources/views/livewire/admin/user-manager.blade.php new file mode 100644 index 0000000..c61387a --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/admin/user-manager.blade.php @@ -0,0 +1,113 @@ +
+
+
+ Manajemen User + Kelola pengguna dan hak akses mereka. +
+ Tambah User +
+ +
+ {{-- Input Pencarian --}} +
+ +
+ + {{-- Filter Role --}} +
+ + + @foreach ($roles as $role) + + @endforeach + +
+
+ + + + Nama + Email + Role + Bergabung Pada + Aksi + + + + @foreach ($users as $user) + + {{ $user->name }} + {{ $user->email }} + + + {{ $user->getRoleNames()->implode(', ') ?: 'Tidak Ada Role' }} + + + {{ $user->created_at->translatedFormat('d F Y') }} + +
+ + @if ($user->id !== auth()->id()) + + @endif +
+
+
+ @endforeach +
+
+ +
+ +
+ + {{-- Modal Form --}} + +
+ {{ $userId ? 'Edit User' : 'User Baru' }} + + + + + + + @foreach ($roles as $role) + + @endforeach + + + + +
+ + Batal + + Simpan User +
+ +
+
+ +@script + +@endscript diff --git a/sk-klinik.my.id/resources/views/livewire/auth/confirm-password.blade.php b/sk-klinik.my.id/resources/views/livewire/auth/confirm-password.blade.php new file mode 100644 index 0000000..13dd110 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/auth/confirm-password.blade.php @@ -0,0 +1,28 @@ + +
+ + + + +
+ @csrf + + + + + {{ __('Confirm') }} + + +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/auth/forgot-password.blade.php b/sk-klinik.my.id/resources/views/livewire/auth/forgot-password.blade.php new file mode 100644 index 0000000..5f1cdad --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/auth/forgot-password.blade.php @@ -0,0 +1,31 @@ + +
+ + + + + +
+ @csrf + + + + + + {{ __('Email password reset link') }} + + + +
+ {{ __('Or, return to') }} + {{ __('log in') }} +
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/auth/login.blade.php b/sk-klinik.my.id/resources/views/livewire/auth/login.blade.php new file mode 100644 index 0000000..e28c998 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/auth/login.blade.php @@ -0,0 +1,59 @@ + +
+ + + + + +
+ @csrf + + + + + +
+ + + @if (Route::has('password.request')) + + {{ __('Forgot your password?') }} + + @endif +
+ + + + +
+ + {{ __('Log in') }} + +
+ + + @if (Route::has('register') && \App\Models\Setting::get('registration_open') == 'true') +
+ {{ __('Don\'t have an account?') }} + {{ __('Sign up') }} +
+ @endif +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/auth/register.blade.php b/sk-klinik.my.id/resources/views/livewire/auth/register.blade.php new file mode 100644 index 0000000..6c12579 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/auth/register.blade.php @@ -0,0 +1,67 @@ + +
+ + + + + +
+ @csrf + + + + + + + + + + + + +
+ + {{ __('Create account') }} + +
+ + +
+ {{ __('Already have an account?') }} + {{ __('Log in') }} +
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/auth/reset-password.blade.php b/sk-klinik.my.id/resources/views/livewire/auth/reset-password.blade.php new file mode 100644 index 0000000..e649471 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/auth/reset-password.blade.php @@ -0,0 +1,52 @@ + +
+ + + + + +
+ @csrf + + + + + + + + + + + + +
+ + {{ __('Reset password') }} + +
+ +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/auth/two-factor-challenge.blade.php b/sk-klinik.my.id/resources/views/livewire/auth/two-factor-challenge.blade.php new file mode 100644 index 0000000..0726c0b --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/auth/two-factor-challenge.blade.php @@ -0,0 +1,95 @@ + +
+
+
+ +
+ +
+ +
+ +
+ @csrf + +
+
+
+ +
+
+ +
+
+ +
+ + @error('recovery_code') + + {{ $message }} + + @enderror +
+ + + {{ __('Continue') }} + +
+ +
+ {{ __('or you can') }} +
+ {{ __('login using a recovery code') }} + {{ __('login using an authentication code') }} +
+
+
+
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/auth/verify-email.blade.php b/sk-klinik.my.id/resources/views/livewire/auth/verify-email.blade.php new file mode 100644 index 0000000..50e7b44 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/auth/verify-email.blade.php @@ -0,0 +1,29 @@ + +
+ + {{ __('Please verify your email address by clicking on the link we just emailed to you.') }} + + + @if (session('status') == 'verification-link-sent') + + {{ __('A new verification link has been sent to the email address you provided during registration.') }} + + @endif + +
+
+ @csrf + + {{ __('Resend verification email') }} + +
+ +
+ @csrf + + {{ __('Log out') }} + +
+
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/about-page.blade.php b/sk-klinik.my.id/resources/views/livewire/guest/about-page.blade.php new file mode 100644 index 0000000..457220a --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/about-page.blade.php @@ -0,0 +1,191 @@ +
+ + {{-- ===================== --}} + {{-- HERO --}} + {{-- ===================== --}} +
+ @php + $accent = $site->accent ?? 'emerald'; + + $colors = [ + 'emerald' => '16,185,129', + 'blue' => '59,130,246', + 'red' => '239,68,68', + 'amber' => '245,158,11', + ]; + + $rgb = $colors[$accent] ?? '16,185,129'; + @endphp +
+ + {{-- ✅ Layer gambar + gradient --}} +
+
+ + {{-- ✅ Konten --}} +
+ + + Profil Klinik + + + + Klinik Sahabat Keluarga + + + + Klinik terpercaya sejak 2009 dengan pelayanan profesional, efektif, dan kekeluargaan. + + +
+ +
+
+ +
+
+ + {{-- ===================== --}} + {{-- TENTANG KAMI --}} + {{-- ===================== --}} +
+
+ Tentang Kami + + Klinik Sahabat Keluarga adalah klinik rawat inap yang berdiri sejak 2009. Kami berkomitmen + memberikan pelayanan kesehatan profesional, efektif, dan terjangkau untuk keluarga Anda. + +
+ +
+ + {{-- IDENTITAS --}} +
+ + + Informasi Klinik +
+

Pemilik: Efin Sulistyorini, S.Si, M.Si

+

Penanggung Jawab: dr. Jaean

+

Berdiri: 2009

+

Jenis: Klinik Rawat Inap

+
+
+ + + Alamat +

+ Jl. Raya Nganjuk - Madiun
+ Kedondong, Bagor - Nganjuk +

+
+ +
+ + {{-- VISI MISI --}} +
+ + + Visi +

+ Menjadi klinik dengan pelayanan profesional, efektif, + efisien, kekeluargaan, dan terjangkau. +

+
+ + + Misi +
    +
  • • Pelayanan berfokus pada pasien
  • +
  • • Pelayanan ramah & nyaman
  • +
  • • Tenaga medis profesional, berpengalaman, dan komunikatif
  • +
  • • One Stop Service untuk pemeriksaan, tindakan, dan obat-obatan
  • +
+
+ +
+ + {{-- ===================== --}} + {{-- TIM KLINIK --}} + {{-- ===================== --}} +
+
+ Tim Kami + + Tenaga profesional yang siap melayani Anda dengan sepenuh hati. + +
+ +
+ + + Dokter +
    +
  • Dr. Jaean (Pimpinan)
  • +
  • Dr. Andriawan Purwantoko
  • +
  • Dr. Risma Adistasari
  • +
  • Dr. Annora
  • +
+
+ + + Perawat +
    +
  • Maryuni S.Kep, Ners
  • +
  • Lilis Maisaroh Amd.Kep
  • +
  • Mira Fanesti Amd.Kep
  • +
  • Ima Nur Kholifah Amd.Kep
  • +
+
+ + + Bidan +
    +
  • Lusi Dwi S, Amd.Keb
  • +
  • Widawati Amd.Keb
  • +
  • Mundiatus Amd.Keb
  • +
  • Erlina Amd.Keb
  • +
+
+ + + Farmasi +
    +
  • Siska Dwi H, Apt.Farm
  • +
  • Rahma Nur Azizah
  • +
  • Jovanka
  • +
+
+ + + Tim Pendukung +
    +
  • Admin: Atik Setiawan
  • +
  • CS: Fahmi, Fabian
  • +
  • Driver: Alif
  • +
  • Satpam: Nugroho
  • +
+
+ +
+
+
+
+ +
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/complete-profile.blade.php b/sk-klinik.my.id/resources/views/livewire/guest/complete-profile.blade.php new file mode 100644 index 0000000..ce9626c --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/complete-profile.blade.php @@ -0,0 +1,97 @@ +
+
+ Lengkapi Profil Pengunjung + Mohon lengkapi data medis Anda untuk mendapatkan layanan kesehatan kami. +
+ +
+ {{-- Seksi Identitas Dasar --}} +
+ Informasi Identitas + + +
+ + +
+ + + + + + + + + + + + + + +
+
+ +
+ + +
+
+ + {{-- Seksi Kontak --}} +
+ Informasi Kontak + + + + +
+ + {{-- Seksi Kontak Darurat --}} +
+ Kontak Darurat (Opsional) + +
+ + + +
+
+ + {{-- Letakkan setelah Seksi Kontak --}} +
+ Metode Pembayaran / Penjamin + + +
+ {{-- Pilihan Jenis Penjamin --}} + + Jenis Penjaminan + + + + + + + + {{-- Input Nomor Kartu (Hanya muncul jika bukan Umum) --}} + @if ($insurance_type !== 'Umum') + + + + + @endif +
+
+ +
+ + Simpan Profil & Lanjutkan + +
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/dashboard.blade.php b/sk-klinik.my.id/resources/views/livewire/guest/dashboard.blade.php new file mode 100644 index 0000000..a76426f --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/dashboard.blade.php @@ -0,0 +1,3 @@ +
+

{{ __('Dashboard') }}

+
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/doctor-page.blade.php b/sk-klinik.my.id/resources/views/livewire/guest/doctor-page.blade.php new file mode 100644 index 0000000..ffc1f67 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/doctor-page.blade.php @@ -0,0 +1,51 @@ +
+
+ Dokter Kami + Tim medis profesional siap melayani Anda +
+ +
+ @foreach($doctors as $doctor) + + {{-- Foto Dokter --}} +
+ +
+ + {{ $doctor->name }} + +
+ + {{ $doctor->specialization }} + +
+ + {{-- Bagian Jadwal --}} +
+

Jadwal Praktik

+ +
+ @php + // Ambil hanya hari yang ada isinya + $activeSchedules = collect($doctor->schedule)->filter(fn($time) => !empty($time)); + @endphp + + @forelse($activeSchedules as $day => $time) +
+ {{ $day }} + {{ $time }} +
+ @empty +

Jadwal belum tersedia

+ @endforelse +
+
+ + {{--
+ Buat Janji Temu +
--}} +
+ @endforeach +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy 2.php b/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy 2.php new file mode 100644 index 0000000..f6c856b --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy 2.php @@ -0,0 +1,243 @@ + + +
+ {{-- 1. Hero Section --}} +
+ @php + $accent = $site->accent ?? 'emerald'; + + $colors = [ + 'emerald' => '16,185,129', + 'blue' => '59,130,246', + 'red' => '239,68,68', + 'amber' => '245,158,11', + ]; + + $rgb = $colors[$accent] ?? '16,185,129'; + @endphp +
+ + {{-- ✅ Layer gambar + gradient --}} +
+
+ + {{-- ✅ Konten --}} +
+ + + Terakreditasi Paripurna + + + + Selamat Datang di {{ $settings['site_name'] ?? 'Klinik Kami' }} + + + + {{ $settings['site_description'] ?? 'Melayani kesehatan keluarga dengan teknologi modern.' }} + + +
+ @if (($settings['registration_open'] ?? 'false') === 'true') + + Daftar Pasien Baru + + @endif + + + Selengkapnya + +
+ +
+ + {{-- dekorasi --}} +
+
+
+ +
+
+ + {{-- 2. Features/Services --}} +
+ + {{-- Header --}} +
+ + Layanan Klinik + + + + Kami menyediakan berbagai layanan kesehatan untuk memenuhi kebutuhan Anda dan keluarga. + +
+ + {{-- Grid --}} +
+ + @foreach ($services as $category) +
+ + {{-- Header --}} +
+ + {{-- Icon --}} +
+ +
+ +
+ + {{ $category->name }} + +

+ {{ $category->services->count() }} layanan +

+
+ +
+ + {{-- List --}} +
    + + @foreach ($category->services->take(5) as $service) +
  • + + + • + + + {{ $service->name }} + +
  • + @endforeach + +
+ + {{-- Footer --}} + @if ($category->services->count() > 5) +
+ +
+ @endif + +
+ @endforeach + +
+
+ + {{-- 3. Contact & Information Section --}} +
+
+
+ Informasi Kontak + Butuh bantuan medis? Hubungi nomor darurat atau kunjungi lokasi kami. +
+ + {{-- bg-zinc-50/50 diubah agar adaptif di dark mode --}} + + {{-- Alamat --}} +
+ +
+

Lokasi Klinik

+

+ {{ $settings['clinic_address'] }}

+ + Salin Alamat + +
+
+ + + + {{-- Telepon --}} +
+ +
+

Telepon & WhatsApp

+

{{ $settings['clinic_phone'] }}

+
+
+ + + + {{-- Media Sosial --}} +
+
+ +
+

Ikuti Kami

+
+
+
+ Facebook + Instagram + Twitter / X +
+
+
+
+ + {{-- 4. Google Maps Section --}} +
+
+ +
+ +
+ + Buka di Maps + +
+
+
+ + {{-- 5. FAQ / Footer Teaser --}} +
+ Siap Memulai Konsultasi? + Bergabunglah dengan ribuan pasien lainnya yang telah mempercayakan kesehatannya + kepada kami. + Buat Akun Sekarang +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy.php b/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy.php new file mode 100644 index 0000000..c347c7f --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade copy.php @@ -0,0 +1,205 @@ + + +
+ {{-- 1. Hero Section --}} +
+ +
+ {{-- Badge: Menghilangkan inset agar tidak bertabrakan dengan padding section --}} + + Terakreditasi Paripurna + + + + Selamat Datang di {{ $settings['site_name'] ?? 'Klinik Kami' }} + + + {{-- Subheading: Menggunakan opacity yang lebih aman agar teks tetap terbaca di bg gelap --}} + + {{ $settings['site_description'] ?? 'Melayani kesehatan keluarga dengan teknologi modern.' }} + + +
+ @if (($settings['registration_open'] ?? 'false') === 'true') + + Daftar Pasien Baru + + @endif + + {{-- Tombol Outline: Diperhalus agar tidak terlalu kaku --}} + Selengkapnya +
+
+ + {{-- Dekorasi Abstract: Dibuat lebih halus --}} +
+
+
+ + {{-- 2. Features/Services --}} +
+ + {{-- Header --}} +
+ + Layanan Klinik + + + + Kami menyediakan berbagai layanan kesehatan untuk memenuhi kebutuhan Anda dan keluarga. + +
+ + {{-- Grid --}} +
+ + @foreach ($services as $category) +
+ + {{-- Header --}} +
+ + {{-- Icon --}} +
+ +
+ +
+ + {{ $category->name }} + +

+ {{ $category->services->count() }} layanan +

+
+ +
+ + {{-- List --}} +
    + + @foreach ($category->services->take(5) as $service) +
  • + + + • + + + {{ $service->name }} + +
  • + @endforeach + +
+ + {{-- Footer --}} + @if ($category->services->count() > 5) +
+ +
+ @endif + +
+ @endforeach + +
+
+ + {{-- 3. Contact & Information Section --}} +
+
+
+ Informasi Kontak + Butuh bantuan medis? Hubungi nomor darurat atau kunjungi lokasi kami. +
+ + {{-- bg-zinc-50/50 diubah agar adaptif di dark mode --}} + + {{-- Alamat --}} +
+ +
+

Lokasi Klinik

+

+ {{ $settings['clinic_address'] }}

+ + Salin Alamat + +
+
+ + + + {{-- Telepon --}} +
+ +
+

Telepon & WhatsApp

+

{{ $settings['clinic_phone'] }}

+
+
+ + + + {{-- Media Sosial --}} +
+
+ +
+

Ikuti Kami

+
+
+
+ Facebook + Instagram + Twitter / X +
+
+
+
+ + {{-- 4. Google Maps Section --}} +
+
+ +
+ +
+ + Buka di Maps + +
+
+
+ + {{-- 5. FAQ / Footer Teaser --}} +
+ Siap Memulai Konsultasi? + Bergabunglah dengan ribuan pasien lainnya yang telah mempercayakan kesehatannya + kepada kami. + Buat Akun Sekarang +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade.php b/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade.php new file mode 100644 index 0000000..4eea1e5 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/landing-page.blade.php @@ -0,0 +1,261 @@ +
{{-- Root Element Utama --}} + + +
+ + {{-- 1. Hero Section (Full Width) --}} +
+ @php + $accent = $site->accent ?? 'emerald'; + $colors = [ + 'emerald' => '16,185,129', + 'blue' => '59,130,246', + 'red' => '239,68,68', + 'amber' => '245,158,11', + ]; + $rgb = $colors[$accent] ?? '16,185,129'; + @endphp + +
+
+
+ +
+
+ + Terakreditasi Paripurna + + + + Selamat Datang di {{ $settings['site_name'] ?? 'Klinik Kami' }} + + + + {{ $settings['site_description'] ?? 'Melayani kesehatan keluarga dengan teknologi modern.' }} + + +
+ @if (($settings['registration_open'] ?? 'false') === 'true') + + Daftar Pasien Baru + + @endif + + Lihat Layanan + +
+
+
+ +
+
+
+
+ + {{-- 2. Features/Services --}} +
+
+ Layanan Klinik + Kami menyediakan berbagai layanan kesehatan untuk memenuhi kebutuhan Anda dan keluarga. +
+ +
+ @foreach ($services as $category) +
+
+
+ +
+
+ {{ $category->name }} +

{{ $category->services->count() }} layanan

+
+
+ +
    + @foreach ($category->services as $service) +
  • + +
    + @if($service->photo) + @php $photos = is_array($service->photo) ? $service->photo : json_decode($service->photo, true); @endphp + + @else +
    + + + +
    + @endif +
    + +
    + + {{ $service->name }} + +
    +
  • + @endforeach +
+ + @if ($category->services->count() > 5) +
+ +
+ @endif +
+ @endforeach +
+
+ + {{-- 3. Contact & Information Section --}} +
+
+
+ Informasi Kontak + Butuh bantuan medis? Hubungi nomor darurat atau kunjungi lokasi kami. +
+ + +
+ +
+

Lokasi Klinik

+

{{ $settings['clinic_address'] ?? '' }}

+ Salin Alamat +
+
+ + + + @php + $phone = $settings['clinic_phone'] ?? ''; + // Hapus karakter selain angka + $cleanPhone = preg_replace('/[^0-9]/', '', $phone); + // Jika diawali angka 0, ganti dengan 62 + if (str_starts_with($cleanPhone, '0')) { + $cleanPhone = '62' . substr($cleanPhone, 1); + } + @endphp +
+ + +
+ + + +
+
+ +

Ikuti Kami

+
+
+ Facebook + Instagram + Twitter / X +
+
+
+
+ + {{-- 4. Google Maps Section --}} +
+
+ +
+ +
+ + Buka di Maps + +
+
+
+ + {{-- 5. FAQ / Footer Teaser --}} +
+ Siap Memulai Konsultasi? + Bergabunglah dengan ribuan pasien lainnya yang telah mempercayakan kesehatannya kepada kami. + Buat Akun Sekarang +
+
+ + {{-- DETAIL MODAL (Murni Hanya Menampilkan Data / Read-Only) --}} + + @if ($selectedService) +
+ {{-- Bagian Header Gambar (Jika ada foto di database) --}} + @if($selectedService->photo) + @php + $modalPhotos = is_array($selectedService->photo) ? $selectedService->photo : json_decode($selectedService->photo, true); + @endphp + @if(!empty($modalPhotos[0])) +
+ +
+ @endif + @endif + + {{-- Informasi Kategori & Judul Layanan --}} +
+ + {{ $selectedService->category?->name ?? 'Layanan Klinik' }} + + + {{ $selectedService->name }} + +
+ + {{-- Deskripsi Layanan --}} +
+

Deskripsi Layanan

+
+ {{ $selectedService->description ?? 'Tidak ada deskripsi tambahan untuk layanan ini.' }} +
+
+ + {{-- Footer Tombol Tutup --}} +
+ + + Tutup + +
+
+ @else + {{-- State Loading saat menunggu pengiriman data dari Server ke DOM --}} +
+ + + + + Memuat rincian data... +
+ @endif +
+ +
\ No newline at end of file diff --git a/sk-klinik.my.id/resources/views/livewire/guest/news-index.blade.php b/sk-klinik.my.id/resources/views/livewire/guest/news-index.blade.php new file mode 100644 index 0000000..c9a2c99 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/news-index.blade.php @@ -0,0 +1,57 @@ +
+ {{-- Header Berita --}} +
+ Berita & Edukasi Kesehatan + Informasi terbaru, tips sehat, dan update layanan dari {{ $site->name }} +
+ + {{-- Grid Berita --}} +
+ {{-- Nanti di-loop dari database --}} + @forelse($news as $item) + +
+ {{-- Placeholder Image jika belum ada --}} + +
+ +
+
+ + {{ $item->category->name ?? 'Uncategorized' }} + + {{ $item->created_at->format('d M Y') }} +
+ + + {{ $item->title }} + + +

+ {{ Str::limit(strip_tags($item->content), 120) }} +

+ +
+ + Baca Selengkapnya + +
+
+
+ @empty + {{-- Tampilan jika belum ada berita --}} +
+ + Belum ada berita + Nantikan informasi menarik dari kami segera. +
+ @endforelse +
+ + {{-- Pagination --}} +
+ {{ $news->links() }} +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/guest/news-show.blade.php b/sk-klinik.my.id/resources/views/livewire/guest/news-show.blade.php new file mode 100644 index 0000000..b2bafe6 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/guest/news-show.blade.php @@ -0,0 +1,67 @@ +
+ {{-- Tombol Kembali --}} +
+ + Kembali ke Berita + +
+ + {{-- Header Berita --}} +
+
+ + {{ $news->category->name ?? 'Uncategorized' }} + + {{ $news->created_at->format('d M Y') }} +
+ + + {{ $news->title }} + + +
+
+ +
+
+

Admin Klinik

+

{{ $news->view_count }}x dibaca

+
+
+
+ + {{-- Gambar Utama --}} + @if ($news->image) +
+ {{ $news->title }} +
+ @endif + + {{-- Konten Berita --}} + {{-- Class 'prose' sangat penting agar styling HTML dari editor (bold, list, h2) muncul --}} +
+ {!! $news->content !!} +
+ + {{-- Footer Berita / Share --}} +
+
+
+ Bagikan Informasi Ini + Bantu orang lain mendapatkan edukasi kesehatan yang tepat. +
+
+ + WhatsApp + + + Salin Link + +
+
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/patient/booking-antrean.blade.php b/sk-klinik.my.id/resources/views/livewire/patient/booking-antrean.blade.php new file mode 100644 index 0000000..52b7e60 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/patient/booking-antrean.blade.php @@ -0,0 +1,241 @@ +
+ {{-- Header --}} +
+
+ Booking & Monitor Antrean Klinik + Pantau antrean berjalan dan ambil nomor antrean Anda. +
+ + {{-- Filter untuk Monitor --}} +
+ + Semua Dokter + @foreach (\App\Models\Doctor::all() as $doc) + {{ $doc->name }} + @endforeach + +
+
+ + + + {{-- MONITOR ANTREAN SEKARANG --}} +
+
+
+
+ +
+
+

Dipanggil Sekarang

+

+ {{ $currentCalling ? $currentCalling->doctor->name : 'Monitor Antrean' }} +

+

+ {{ $currentCalling ? $currentCalling->serviceCategory->name : 'Silakan pilih dokter untuk monitor spesifik' }} +

+
+
+ +
+
+ {{-- ID: calling-number untuk dideteksi script --}} +
+ {{ $currentCalling ? str_pad($currentCalling->queue_number, 2, '0', STR_PAD_LEFT) : '--' }} +
+
+ + + +
+ @if ($currentCalling) +

Nama Pasien

+ {{-- ID: calling-name untuk dibaca script --}} +

+ {{ Str::limit($currentCalling->patient->name, 20) }} +

+ @else +

Belum ada pemanggilan

+ @endif +
+
+ + +
+
+ +
+ {{-- Sisi Kiri: Form Booking --}} +
+ +
+ Buat Janji Temu + Lengkapi data di bawah ini. +
+ +
+ + + + Pilih Poli... + @foreach ($categories as $cat) + {{ $cat->name }} + @endforeach + + + + Pilih Dokter... + @foreach ($doctors as $doc) + {{ $doc->name }} + @endforeach + + + + Ambil Antrean + + +
+
+ + {{-- Sisi Kanan: Daftar Antrean Saya --}} +
+ +
+ Riwayat Antrean Saya + Daftar antrean Anda yang aktif maupun yang sudah selesai. +
+ + + + No. Antre + Tanggal + Status + Keluhan Singkat + Aksi + + + + @forelse ($myAppointments as $app) + + + + #{{ $app->queue_number }} + + + + {{ $app->appointment_date->translatedFormat('d F Y') }} + + + @php + $statusConfig = match ($app->status) { + 'waiting' => ['color' => 'yellow', 'label' => 'Menunggu'], + 'calling' => ['color' => 'blue', 'label' => 'Dipanggil'], + 'finished' => ['color' => 'green', 'label' => 'Selesai'], + 'cancelled' => ['color' => 'red', 'label' => 'Batal'], + default => ['color' => 'zinc', 'label' => $app->status], + }; + @endphp + + {{ strtoupper($statusConfig['label']) }} + + + + {{ Str::limit($app->notes, 30) }} + + + + + + @empty + + Belum ada data + antrean. + + @endforelse + + +
+
+
+ + {{-- MODAL KARTU ANTREAN (Tetap sama) --}} + + @if ($selectedAppointment) +
+
+ + {{ $site->name ?? 'KLINIK' }} + + Bukti Antrean Digital +
+
+
+ Nomor Antrean +
+ {{ str_pad($selectedAppointment->queue_number, 3, '0', STR_PAD_LEFT) }} +
+
+
+ + Tutup +
+
+
+ @endif +
+ + {{-- SCRIPT SUARA PANGGILAN --}} + +
diff --git a/sk-klinik.my.id/resources/views/livewire/patient/complete-profile.blade.php b/sk-klinik.my.id/resources/views/livewire/patient/complete-profile.blade.php new file mode 100644 index 0000000..6e37fcc --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/patient/complete-profile.blade.php @@ -0,0 +1,97 @@ +
+
+ Lengkapi Profil Pasien + Mohon lengkapi data medis Anda untuk mendapatkan layanan kesehatan kami. +
+ +
+ {{-- Seksi Identitas Dasar --}} +
+ Informasi Identitas + + +
+ + +
+ + + + + + + + + + + + + + +
+
+ +
+ + +
+
+ + {{-- Seksi Kontak --}} +
+ Informasi Kontak + + + + +
+ + {{-- Seksi Kontak Darurat --}} +
+ Kontak Darurat (Opsional) + +
+ + + +
+
+ + {{-- Letakkan setelah Seksi Kontak --}} +
+ Metode Pembayaran / Penjamin + + +
+ {{-- Pilihan Jenis Penjamin --}} + + Jenis Penjaminan + + + + + + + + {{-- Input Nomor Kartu (Hanya muncul jika bukan Umum) --}} + @if ($insurance_type !== 'Umum') + + + + + @endif +
+
+ +
+ + Simpan Profil & Lanjutkan + +
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/patient/dashboard.blade.php b/sk-klinik.my.id/resources/views/livewire/patient/dashboard.blade.php new file mode 100644 index 0000000..07a8f8d --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/patient/dashboard.blade.php @@ -0,0 +1,115 @@ +
+ {{-- Welcome Section --}} +
+
+ Halo, {{ auth()->user()->name }}! 👋 + Semoga sehat selalu hari ini. +
+ + Buat Janji Temu + +
+ +
+ {{-- Status Antrean Hari Ini --}} +
+ Janji Temu Hari Ini + + @if ($currentAppointment) + +
+
+
+ No. Antrean + + {{ $currentAppointment->queue_number }} +
+
+ {{ $currentAppointment->serviceCategory->name }} + Dokter: {{ $currentAppointment->doctor->name ?? 'Akan ditentukan' }} + +
+ + {{ strtoupper($currentAppointment->status) }} + +
+
+
+
+ Tanggal Sesi + + {{ \Carbon\Carbon::parse($currentAppointment->appointment_date)->translatedFormat('d F Y') }} + +
+
+
+ @else + + + Tidak ada jadwal hari ini + Silakan buat janji temu jika Anda merasa kurang sehat. + + @endif + + {{-- Riwayat Singkat --}} +
+ Riwayat Berobat Terakhir + + + Tanggal + Layanan + Status + + + @forelse($history as $item) + + + {{ \Carbon\Carbon::parse($item->appointment_date)->translatedFormat('d M Y') }} + + {{ $item->serviceCategory->name }} + + {{ $item->status }} + + + @empty + + + + Belum ada riwayat berobat. + + + @endforelse + + +
+
+ + {{-- Sidebar: Berita Kesehatan --}} +
+ Info Kesehatan + @forelse ($news as $article) + + + @if ($article->image) + + @endif +
+ {{ $article->title }} + + + {{ Str::limit(strip_tags($article->content), 80) }} +
+
+
+ @empty +
+ + Tidak ada berita kesehatan. + Silakan cek kembali nanti untuk informasi terbaru. +
+ @endforelse +
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/patient/news/news-detail.blade.php b/sk-klinik.my.id/resources/views/livewire/patient/news/news-detail.blade.php new file mode 100644 index 0000000..1b35647 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/patient/news/news-detail.blade.php @@ -0,0 +1,64 @@ +
+ {{-- Breadcrumbs --}} + + +
+ {{-- Header --}} +
+ + {{ $news->category->name }} + + + + {{ $news->title }} + + +
+
+ + {{ $news->created_at->format('d M Y') }} +
+
+
+ + {{ $news->read_time ?? '5' }} Menit Baca +
+
+
+ + {{-- Featured Image --}} + @if($news->image) +
+ {{ $news->title }} +
+ @endif + + {{-- Content --}} +
+ {!! $news->content !!} +
+ + {{-- Footer/Share --}} +
+ + Kembali ke Daftar + + +
+ {{-- Tombol Share Sederhana --}} + + Salin Link + +
+
+
+
diff --git a/sk-klinik.my.id/resources/views/livewire/patient/news/news.blade.php b/sk-klinik.my.id/resources/views/livewire/patient/news/news.blade.php new file mode 100644 index 0000000..50bd08f --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/patient/news/news.blade.php @@ -0,0 +1,79 @@ +
+ +
+
+ Berita & Artikel Kesehatan + Dapatkan informasi kesehatan terpercaya dari tim dokter kami. +
+ +
+ +
+
+ + @if($news->count() > 0) +
+ @foreach($news as $item) +
+ +
+ @if($item->image) + {{ $item->title }} + @else +
+ +
+ @endif + +
+ + {{ $item->category->name }} + +
+
+ +
+
+ {{ $item->created_at->format('d M Y') }} + + {{ $item->read_time ?? '5' }} mnt baca +
+ + + + {{ $item->title }} + + + +

+ {{ Str::limit(strip_tags($item->content), 120) }} +

+ +
+ + Baca Selengkapnya + +
+
+
+ @endforeach +
+ +
+ {{ $news->links() }} +
+ @else +
+
+ +
+ Berita tidak ditemukan + Coba kata kunci lain atau periksa kategori yang berbeda. +
+ @endif +
diff --git a/sk-klinik.my.id/resources/views/livewire/patient/patient-profile.blade.php b/sk-klinik.my.id/resources/views/livewire/patient/patient-profile.blade.php new file mode 100644 index 0000000..922b5fd --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/patient/patient-profile.blade.php @@ -0,0 +1,138 @@ +
+ {{-- Kartu Pasien Digital --}} +
+
+
+

KARTU PASIEN DIGITAL

+

Klinik Digital System

+
+ +
+ +
+
+

Nama Pasien

+

{{ auth()->user()->name }}

+
+
+
+

NIK

+

{{ $patient->nik }}

+
+
+

Gol. Darah

+

{{ $patient->blood_type ?? '-' }}

+
+
+
+ +
+ +
+
+ + {{-- Form Edit Data Lengkap --}} +
+ +
+ Update Informasi Profil + + {{-- Informasi Identitas --}} +
+ Informasi Identitas + + + +
+ + + + + + + +
+ +
+ + +
+ +
+ + + + + + + + + + + + +
+
+ + {{-- Informasi Kontak --}} +
+ Kontak & Alamat + + + + + +
+ + {{-- Penjamin --}} +
+ Metode Pembayaran + + + +
+ + + + + + + @if ($insurance_type !== 'Umum') + + @endif +
+
+ + {{-- Kontak Darurat --}} +
+ Kontak Darurat + +
+ + + +
+
+ +
+ + Simpan Perubahan Profil + +
+
+
+
+ +
+ Pastikan informasi di atas selalu diperbarui untuk memudahkan proses pelayanan di klinik. +
+ +
+ + Unduh Kartu (PDF/Cetak) + +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/settings/appearance.blade.php b/sk-klinik.my.id/resources/views/livewire/settings/appearance.blade.php new file mode 100644 index 0000000..86c7ec7 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/settings/appearance.blade.php @@ -0,0 +1,13 @@ +
+ @include('partials.settings-heading') + + {{ __('Appearance settings') }} + + + + {{ __('Light') }} + {{ __('Dark') }} + {{ __('System') }} + + +
diff --git a/sk-klinik.my.id/resources/views/livewire/settings/delete-user-form.blade.php b/sk-klinik.my.id/resources/views/livewire/settings/delete-user-form.blade.php new file mode 100644 index 0000000..a641407 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/settings/delete-user-form.blade.php @@ -0,0 +1,34 @@ +
+
+ {{ __('Delete account') }} + {{ __('Delete your account and all of its resources') }} +
+ + + + {{ __('Delete account') }} + + + + +
+
+ {{ __('Are you sure you want to delete your account?') }} + + + {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }} + +
+ + + +
+ + {{ __('Cancel') }} + + + {{ __('Delete account') }} +
+ +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/settings/profile.blade.php b/sk-klinik.my.id/resources/views/livewire/settings/profile.blade.php new file mode 100644 index 0000000..3b36a74 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/settings/profile.blade.php @@ -0,0 +1,47 @@ +
+ @include('partials.settings-heading') + + {{ __('Profile settings') }} + + +
+ + +
+ + + @if ($this->hasUnverifiedEmail) +
+ + {{ __('Your email address is unverified.') }} + + + {{ __('Click here to re-send the verification email.') }} + + + + @if (session('status') === 'verification-link-sent') + + {{ __('A new verification link has been sent to your email address.') }} + + @endif +
+ @endif +
+ +
+
+ {{ __('Save') }} +
+ + + {{ __('Saved.') }} + +
+ + + @if ($this->showDeleteUser) + + @endif +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/settings/security.blade.php b/sk-klinik.my.id/resources/views/livewire/settings/security.blade.php new file mode 100644 index 0000000..9e973d3 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/settings/security.blade.php @@ -0,0 +1,239 @@ +
+ @include('partials.settings-heading') + + {{ __('Security settings') }} + + +
+ + + + +
+
+ {{ __('Save') }} +
+ + + {{ __('Saved.') }} + +
+ + + @if ($canManageTwoFactor) +
+ {{ __('Two-factor authentication') }} + {{ __('Manage your two-factor authentication settings') }} + +
+ @if ($twoFactorEnabled) +
+ + {{ __('You will be prompted for a secure, random pin during login, which you can retrieve from the TOTP-supported application on your phone.') }} + + +
+ + {{ __('Disable 2FA') }} + +
+ + +
+ @else +
+ + {{ __('When you enable two-factor authentication, you will be prompted for a secure pin during login. This pin can be retrieved from a TOTP-supported application on your phone.') }} + + + + {{ __('Enable 2FA') }} + +
+ @endif +
+
+ + +
+
+
+
+
+ @for ($i = 1; $i <= 5; $i++) +
+ @endfor +
+ +
+ @for ($i = 1; $i <= 5; $i++) +
+ @endfor +
+ + +
+
+ +
+ {{ $this->modalConfig['title'] }} + {{ $this->modalConfig['description'] }} +
+
+ + @if ($showVerificationStep) +
+
+ +
+ +
+ + {{ __('Back') }} + + + + {{ __('Confirm') }} + +
+
+ @else + @error('setupData') + + @enderror + +
+
+ @empty($qrCodeSvg) +
+ +
+ @else +
+
+ {!! $qrCodeSvg !!} +
+
+ @endempty +
+
+ +
+ + {{ $this->modalConfig['buttonText'] }} + +
+ +
+
+
+ + {{ __('or, enter the code manually') }} + +
+ +
+
+ @empty($manualSetupKey) +
+ +
+ @else + + + + @endempty +
+
+
+ @endif +
+
+ @endif +
+
diff --git a/sk-klinik.my.id/resources/views/livewire/settings/two-factor/recovery-codes.blade.php b/sk-klinik.my.id/resources/views/livewire/settings/two-factor/recovery-codes.blade.php new file mode 100644 index 0000000..9ed2674 --- /dev/null +++ b/sk-klinik.my.id/resources/views/livewire/settings/two-factor/recovery-codes.blade.php @@ -0,0 +1,89 @@ +
+
+
+ + {{ __('2FA recovery codes') }} +
+ + {{ __('Recovery codes let you regain access if you lose your 2FA device. Store them in a secure password manager.') }} + +
+ +
+
+ + + + {{ __('Hide recovery codes') }} + + + @if (filled($recoveryCodes)) + + {{ __('Regenerate codes') }} + + @endif +
+ +
+
+ @error('recoveryCodes') + + @enderror + + @if (filled($recoveryCodes)) +
+ @foreach($recoveryCodes as $code) +
+ {{ $code }} +
+ @endforeach +
+ + {{ __('Each recovery code can be used once to access your account and will be removed after use. If you need more, click Regenerate codes above.') }} + + @endif +
+
+
+
diff --git a/sk-klinik.my.id/resources/views/partials/head.blade.php b/sk-klinik.my.id/resources/views/partials/head.blade.php new file mode 100644 index 0000000..4c09266 --- /dev/null +++ b/sk-klinik.my.id/resources/views/partials/head.blade.php @@ -0,0 +1,31 @@ + + + + + {{ filled($title ?? null) ? $title . ' - ' . $site->name : $site->name }} + + + + + + + + + + + + + + + + + + + + + +@vite(['resources/css/app.css', 'resources/js/app.js']) +@fluxAppearance + + +@include('layouts.theme-style') diff --git a/sk-klinik.my.id/resources/views/partials/settings-heading.blade.php b/sk-klinik.my.id/resources/views/partials/settings-heading.blade.php new file mode 100644 index 0000000..925ace9 --- /dev/null +++ b/sk-klinik.my.id/resources/views/partials/settings-heading.blade.php @@ -0,0 +1,5 @@ +
+ {{ __('Settings') }} + {{ __('Manage your profile and account settings') }} + +
diff --git a/sk-klinik.my.id/resources/views/welcome.blade.php b/sk-klinik.my.id/resources/views/welcome.blade.php new file mode 100644 index 0000000..c7b6eb4 --- /dev/null +++ b/sk-klinik.my.id/resources/views/welcome.blade.php @@ -0,0 +1,278 @@ + + + + + + + {{ __('Welcome') }} - {{ config('app.name', 'Laravel') }} + + + + + + + + + + + + + +
+ @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/sk-klinik.my.id/routes/admin.php b/sk-klinik.my.id/routes/admin.php new file mode 100644 index 0000000..f799c65 --- /dev/null +++ b/sk-klinik.my.id/routes/admin.php @@ -0,0 +1,78 @@ +group(function () { + Route::prefix('admin')->group(function () { + Route::livewire('dashboard', \App\Livewire\Admin\Dashboard::class) + ->middleware('permission:view-dashboard') + ->name('admin.dashboard'); + + Route::livewire('patients', \App\Livewire\Admin\PatientManager::class) + ->middleware('permission:patient-manage') + ->name('admin.patients'); + + Route::livewire('patients/{patient}/history', \App\Livewire\Admin\PatientHistory::class) + ->middleware('permission:patient-manage') + ->name('admin.patients.history'); + + Route::get('patients/{patient}/print', [App\Http\Controllers\Admin\PatientController::class, 'print']) + ->middleware('permission:patient-print') + ->name('admin.patients.print'); + + Route::livewire('settings', \App\Livewire\Admin\SiteSettings::class) + ->middleware('permission:settings-manage') + ->name('admin.settings'); + + Route::livewire('roles', \App\Livewire\Admin\RoleManager::class) + ->middleware('permission:role-manage') + ->name('admin.roles'); + + Route::livewire('roles/{role}/permissions', \App\Livewire\Admin\RolePermissions::class) + ->middleware('permission:role-manage') + ->name('admin.roles.permissions'); + + Route::get('permissions', \App\Livewire\Admin\PermissionManager::class) + ->middleware('permission:permission-manage') + ->name('admin.permissions'); + + Route::livewire('users', \App\Livewire\Admin\UserManager::class) + ->middleware('permission:user-manage') + ->name('admin.users'); + + // Manajemen Kategori + Route::get('/categories', App\Livewire\Admin\Categories::class) + ->middleware('permission:category-manage') + ->name('admin.categories'); + + // Manajemen Berita + Route::get('/news', App\Livewire\Admin\News::class) + ->middleware('permission:news-manage') + ->name('admin.news'); + Route::get('/news/create', App\Livewire\Admin\NewsCreate::class) + ->middleware('permission:news-manage') + ->name('admin.news.create'); + Route::get('/news/{news}/edit', App\Livewire\Admin\NewsEdit::class) + ->middleware('permission:news-manage') + ->name('admin.news.edit'); + + // Kelola Antrean + Route::get('/antrean', App\Livewire\Admin\ManageAntrean::class) + ->middleware('permission:antrean-manage') + ->name('admin.antrean'); + + // Manajemen Dokter + Route::get('/doctors', App\Livewire\Admin\DoctorManager::class) + ->middleware('permission:doctor-manage') + ->name('admin.doctors'); + + // Manajemen Layanan + Route::get('/services', App\Livewire\Admin\ServiceManager::class) + ->middleware('permission:service-manage') + ->name('admin.services'); + }); +}); diff --git a/sk-klinik.my.id/routes/console.php b/sk-klinik.my.id/routes/console.php new file mode 100644 index 0000000..3c9adf1 --- /dev/null +++ b/sk-klinik.my.id/routes/console.php @@ -0,0 +1,8 @@ +comment(Inspiring::quote()); +})->purpose('Display an inspiring quote'); diff --git a/sk-klinik.my.id/routes/guest.php b/sk-klinik.my.id/routes/guest.php new file mode 100644 index 0000000..a9a87f2 --- /dev/null +++ b/sk-klinik.my.id/routes/guest.php @@ -0,0 +1,9 @@ +group(function () { + Route::prefix('guest')->group(function () { + Route::get('/complete-profile', \App\Livewire\Guest\CompleteProfile::class)->name('guest.complete-profile'); + }); +}); diff --git a/sk-klinik.my.id/routes/patient.php b/sk-klinik.my.id/routes/patient.php new file mode 100644 index 0000000..81bf46c --- /dev/null +++ b/sk-klinik.my.id/routes/patient.php @@ -0,0 +1,22 @@ +group(function () { + Route::prefix('patient')->group(function () { + Route::livewire('dashboard', \App\Livewire\Patient\Dashboard::class) + ->name('patient.dashboard'); + + Route::get('/my-profile', \App\Livewire\Patient\PatientProfile::class)->name('patient.profile'); + Route::get('/complete-profile', \App\Livewire\Patient\CompleteProfile::class)->name('patient.complete-profile'); + + Route::get('{patient}/print', [App\Http\Controllers\Admin\PatientController::class, 'print']) + ->name('patient.patients.print'); + + Route::get('/news', App\Livewire\Patient\News::class) + ->name('patient.news'); + Route::get('/news/{news:slug}', App\Livewire\Patient\NewsDetail::class)->name('patient.news.show'); + + Route::get('/appointment', App\Livewire\Patient\BookingAntrean::class)->name('patient.appointment'); + }); +}); diff --git a/sk-klinik.my.id/routes/settings.php b/sk-klinik.my.id/routes/settings.php new file mode 100644 index 0000000..618957b --- /dev/null +++ b/sk-klinik.my.id/routes/settings.php @@ -0,0 +1,28 @@ +group(function () { + Route::redirect('settings', 'settings/profile'); + + Route::livewire('settings/profile', Profile::class)->name('profile.edit'); +}); + +Route::middleware(['auth', 'verified'])->group(function () { + Route::livewire('settings/appearance', Appearance::class)->name('appearance.edit'); + + Route::livewire('settings/security', Security::class) + ->middleware( + when( + Features::canManageTwoFactorAuthentication() + && Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword'), + ['password.confirm'], + [], + ), + ) + ->name('security.edit'); +}); diff --git a/sk-klinik.my.id/routes/web.php b/sk-klinik.my.id/routes/web.php new file mode 100644 index 0000000..b4a37d8 --- /dev/null +++ b/sk-klinik.my.id/routes/web.php @@ -0,0 +1,66 @@ +name('home'); +Route::get('/', App\Livewire\Guest\LandingPage::class)->name('home'); +// Daftar Berita +Route::get('/berita', App\Livewire\Guest\NewsIndex::class)->name('news.index'); + +// Detail Berita (menggunakan Slug agar SEO Friendly) +Route::get('/berita/{news:slug}', \App\Livewire\Guest\NewsShow::class)->name('news.show'); + +Route::middleware(['auth', 'verified'])->group(function () { + + Route::get('dashboard', function () { + $user = auth()->user(); + + if ($user->hasRole('admin')) { + return redirect()->route('admin.dashboard'); + } + + if ($user->hasRole('patient')) { + return redirect()->route('patient.dashboard'); + } + + if ($user->hasRole('guest')) { + return redirect()->route('guest.complete-profile'); + } + + //return view('dashboard'); + return redirect()->route('admin.dashboard'); + })->middleware(['auth', 'verified'])->name('dashboard'); + +}); + +Route::get('/v/{nik}', [App\Http\Controllers\Admin\PatientController::class, 'verify']) + ->name('verify.patient'); + +Route::get('/doctors', App\Livewire\Guest\DoctorPage::class)->name('doctors.index'); +Route::get('/about', App\Livewire\Guest\AboutPage::class)->name('about'); + +require __DIR__ . '/settings.php'; +require __DIR__ . '/admin.php'; +require __DIR__ . '/guest.php'; +require __DIR__ . '/patient.php'; diff --git a/sk-klinik.my.id/storage/app/.gitignore b/sk-klinik.my.id/storage/app/.gitignore new file mode 100644 index 0000000..fedb287 --- /dev/null +++ b/sk-klinik.my.id/storage/app/.gitignore @@ -0,0 +1,4 @@ +* +!private/ +!public/ +!.gitignore diff --git a/sk-klinik.my.id/storage/app/private/.gitignore b/sk-klinik.my.id/storage/app/private/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/storage/app/private/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/storage/app/public/.gitignore b/sk-klinik.my.id/storage/app/public/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/storage/framework/.gitignore b/sk-klinik.my.id/storage/framework/.gitignore new file mode 100644 index 0000000..05c4471 --- /dev/null +++ b/sk-klinik.my.id/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/sk-klinik.my.id/storage/framework/cache/.gitignore b/sk-klinik.my.id/storage/framework/cache/.gitignore new file mode 100644 index 0000000..01e4a6c --- /dev/null +++ b/sk-klinik.my.id/storage/framework/cache/.gitignore @@ -0,0 +1,3 @@ +* +!data/ +!.gitignore diff --git a/sk-klinik.my.id/storage/framework/cache/data/.gitignore b/sk-klinik.my.id/storage/framework/cache/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/storage/framework/cache/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/storage/framework/sessions/.gitignore b/sk-klinik.my.id/storage/framework/sessions/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/storage/framework/testing/.gitignore b/sk-klinik.my.id/storage/framework/testing/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/storage/framework/testing/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/storage/framework/views/.gitignore b/sk-klinik.my.id/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/storage/logs/.gitignore b/sk-klinik.my.id/storage/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sk-klinik.my.id/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sk-klinik.my.id/tests/Feature/Auth/AuthenticationTest.php b/sk-klinik.my.id/tests/Feature/Auth/AuthenticationTest.php new file mode 100644 index 0000000..4b3411d --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Auth/AuthenticationTest.php @@ -0,0 +1,81 @@ +get(route('login')); + + $response->assertOk(); + } + + public function test_users_can_authenticate_using_the_login_screen(): void + { + $user = User::factory()->create(); + + $response = $this->post(route('login.store'), [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('dashboard', absolute: false)); + + $this->assertAuthenticated(); + } + + public function test_users_can_not_authenticate_with_invalid_password(): void + { + $user = User::factory()->create(); + + $response = $this->post(route('login.store'), [ + 'email' => $user->email, + 'password' => 'wrong-password', + ]); + + $response->assertSessionHasErrorsIn('email'); + + $this->assertGuest(); + } + + public function test_users_with_two_factor_enabled_are_redirected_to_two_factor_challenge(): void + { + $this->skipUnlessFortifyFeature(Features::twoFactorAuthentication()); + + Features::twoFactorAuthentication([ + 'confirm' => true, + 'confirmPassword' => true, + ]); + + $user = User::factory()->withTwoFactor()->create(); + + $response = $this->post(route('login.store'), [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $response->assertRedirect(route('two-factor.login')); + $this->assertGuest(); + } + + public function test_users_can_logout(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post(route('logout')); + + $response->assertRedirect(route('home')); + + $this->assertGuest(); + } +} diff --git a/sk-klinik.my.id/tests/Feature/Auth/EmailVerificationTest.php b/sk-klinik.my.id/tests/Feature/Auth/EmailVerificationTest.php new file mode 100644 index 0000000..c68f31a --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Auth/EmailVerificationTest.php @@ -0,0 +1,88 @@ +skipUnlessFortifyFeature(Features::emailVerification()); + } + + public function test_email_verification_screen_can_be_rendered(): void + { + $user = User::factory()->unverified()->create(); + + $response = $this->actingAs($user)->get(route('verification.notice')); + + $response->assertOk(); + } + + public function test_email_can_be_verified(): void + { + $user = User::factory()->unverified()->create(); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)], + ); + + $response = $this->actingAs($user)->get($verificationUrl); + + Event::assertDispatched(Verified::class); + + $this->assertTrue($user->fresh()->hasVerifiedEmail()); + $response->assertRedirect(route('dashboard', absolute: false).'?verified=1'); + } + + public function test_email_is_not_verified_with_invalid_hash(): void + { + $user = User::factory()->unverified()->create(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1('wrong-email')], + ); + + $this->actingAs($user)->get($verificationUrl); + + $this->assertFalse($user->fresh()->hasVerifiedEmail()); + } + + public function test_already_verified_user_visiting_verification_link_is_redirected_without_firing_event_again(): void + { + $user = User::factory()->create([ + 'email_verified_at' => now(), + ]); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)], + ); + + $this->actingAs($user)->get($verificationUrl) + ->assertRedirect(route('dashboard', absolute: false).'?verified=1'); + + $this->assertTrue($user->fresh()->hasVerifiedEmail()); + Event::assertNotDispatched(Verified::class); + } +} diff --git a/sk-klinik.my.id/tests/Feature/Auth/PasswordConfirmationTest.php b/sk-klinik.my.id/tests/Feature/Auth/PasswordConfirmationTest.php new file mode 100644 index 0000000..b86e36c --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Auth/PasswordConfirmationTest.php @@ -0,0 +1,21 @@ +create(); + + $response = $this->actingAs($user)->get(route('password.confirm')); + + $response->assertOk(); + } +} diff --git a/sk-klinik.my.id/tests/Feature/Auth/PasswordResetTest.php b/sk-klinik.my.id/tests/Feature/Auth/PasswordResetTest.php new file mode 100644 index 0000000..785225f --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Auth/PasswordResetTest.php @@ -0,0 +1,81 @@ +skipUnlessFortifyFeature(Features::resetPasswords()); + } + + public function test_reset_password_link_screen_can_be_rendered(): void + { + $response = $this->get(route('password.request')); + + $response->assertOk(); + } + + public function test_reset_password_link_can_be_requested(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post(route('password.request'), ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class); + } + + public function test_reset_password_screen_can_be_rendered(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post(route('password.request'), ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { + $response = $this->get(route('password.reset', $notification->token)); + + $response->assertOk(); + + return true; + }); + } + + public function test_password_can_be_reset_with_valid_token(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post(route('password.request'), ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { + $response = $this->post(route('password.update'), [ + 'token' => $notification->token, + 'email' => $user->email, + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('login', absolute: false)); + + return true; + }); + } +} diff --git a/sk-klinik.my.id/tests/Feature/Auth/RegistrationTest.php b/sk-klinik.my.id/tests/Feature/Auth/RegistrationTest.php new file mode 100644 index 0000000..4088b30 --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Auth/RegistrationTest.php @@ -0,0 +1,41 @@ +skipUnlessFortifyFeature(Features::registration()); + } + + public function test_registration_screen_can_be_rendered(): void + { + $response = $this->get(route('register')); + + $response->assertOk(); + } + + public function test_new_users_can_register(): void + { + $response = $this->post(route('register.store'), [ + 'name' => 'John Doe', + 'email' => 'test@example.com', + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response->assertSessionHasNoErrors() + ->assertRedirect(route('dashboard', absolute: false)); + + $this->assertAuthenticated(); + } +} diff --git a/sk-klinik.my.id/tests/Feature/Auth/TwoFactorChallengeTest.php b/sk-klinik.my.id/tests/Feature/Auth/TwoFactorChallengeTest.php new file mode 100644 index 0000000..2016f2b --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Auth/TwoFactorChallengeTest.php @@ -0,0 +1,42 @@ +skipUnlessFortifyFeature(Features::twoFactorAuthentication()); + } + + public function test_two_factor_challenge_redirects_to_login_when_not_authenticated(): void + { + $response = $this->get(route('two-factor.login')); + + $response->assertRedirect(route('login')); + } + + public function test_two_factor_challenge_can_be_rendered(): void + { + Features::twoFactorAuthentication([ + 'confirm' => true, + 'confirmPassword' => true, + ]); + + $user = User::factory()->withTwoFactor()->create(); + + $this->post(route('login.store'), [ + 'email' => $user->email, + 'password' => 'password', + ])->assertRedirect(route('two-factor.login')); + } +} diff --git a/sk-klinik.my.id/tests/Feature/DashboardTest.php b/sk-klinik.my.id/tests/Feature/DashboardTest.php new file mode 100644 index 0000000..3c5cd7d --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/DashboardTest.php @@ -0,0 +1,27 @@ +get(route('dashboard')); + $response->assertRedirect(route('login')); + } + + public function test_authenticated_users_can_visit_the_dashboard(): void + { + $user = User::factory()->create(); + $this->actingAs($user); + + $response = $this->get(route('dashboard')); + $response->assertOk(); + } +} diff --git a/sk-klinik.my.id/tests/Feature/ExampleTest.php b/sk-klinik.my.id/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..70d12f0 --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/ExampleTest.php @@ -0,0 +1,18 @@ +get(route('home')); + + $response->assertOk(); + } +} diff --git a/sk-klinik.my.id/tests/Feature/Settings/ProfileUpdateTest.php b/sk-klinik.my.id/tests/Feature/Settings/ProfileUpdateTest.php new file mode 100644 index 0000000..fccf19f --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Settings/ProfileUpdateTest.php @@ -0,0 +1,90 @@ +actingAs($user = User::factory()->create()); + + $this->get('/settings/profile')->assertOk(); + } + + public function test_profile_information_can_be_updated(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test(Profile::class) + ->set('name', 'Test User') + ->set('email', 'test@example.com') + ->call('updateProfileInformation'); + + $response->assertHasNoErrors(); + + $user->refresh(); + + $this->assertEquals('Test User', $user->name); + $this->assertEquals('test@example.com', $user->email); + $this->assertNull($user->email_verified_at); + } + + public function test_email_verification_status_is_unchanged_when_email_address_is_unchanged(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test(Profile::class) + ->set('name', 'Test User') + ->set('email', $user->email) + ->call('updateProfileInformation'); + + $response->assertHasNoErrors(); + + $this->assertNotNull($user->refresh()->email_verified_at); + } + + public function test_user_can_delete_their_account(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test('settings.delete-user-form') + ->set('password', 'password') + ->call('deleteUser'); + + $response + ->assertHasNoErrors() + ->assertRedirect('/'); + + $this->assertNull($user->fresh()); + $this->assertFalse(auth()->check()); + } + + public function test_correct_password_must_be_provided_to_delete_account(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test('settings.delete-user-form') + ->set('password', 'wrong-password') + ->call('deleteUser'); + + $response->assertHasErrors(['password']); + + $this->assertNotNull($user->fresh()); + } +} diff --git a/sk-klinik.my.id/tests/Feature/Settings/SecurityTest.php b/sk-klinik.my.id/tests/Feature/Settings/SecurityTest.php new file mode 100644 index 0000000..2049186 --- /dev/null +++ b/sk-klinik.my.id/tests/Feature/Settings/SecurityTest.php @@ -0,0 +1,123 @@ +skipUnlessFortifyFeature(Features::twoFactorAuthentication()); + + Features::twoFactorAuthentication([ + 'confirm' => true, + 'confirmPassword' => true, + ]); + } + + public function test_security_settings_page_can_be_rendered(): void + { + $user = User::factory()->create(); + + $this->actingAs($user) + ->withSession(['auth.password_confirmed_at' => time()]) + ->get(route('security.edit')) + ->assertOk() + ->assertSee('Two-factor authentication') + ->assertSee('Enable 2FA'); + } + + public function test_security_settings_page_requires_password_confirmation_when_enabled(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user) + ->get(route('security.edit')); + + $response->assertRedirect(route('password.confirm')); + } + + public function test_security_settings_page_renders_without_two_factor_when_feature_is_disabled(): void + { + config(['fortify.features' => []]); + + $user = User::factory()->create(); + + $this->actingAs($user) + ->withSession(['auth.password_confirmed_at' => time()]) + ->get(route('security.edit')) + ->assertOk() + ->assertSee('Update password') + ->assertDontSee('Two-factor authentication'); + } + + public function test_two_factor_authentication_disabled_when_confirmation_abandoned_between_requests(): void + { + $user = User::factory()->create(); + + $user->forceFill([ + 'two_factor_secret' => encrypt('test-secret'), + 'two_factor_recovery_codes' => encrypt(json_encode(['code1', 'code2'])), + 'two_factor_confirmed_at' => null, + ])->save(); + + $this->actingAs($user); + + $component = Livewire::test(Security::class); + + $component->assertSet('twoFactorEnabled', false); + + $this->assertDatabaseHas('users', [ + 'id' => $user->id, + 'two_factor_secret' => null, + 'two_factor_recovery_codes' => null, + ]); + } + + public function test_password_can_be_updated(): void + { + $user = User::factory()->create([ + 'password' => Hash::make('password'), + ]); + + $this->actingAs($user); + + $response = Livewire::test(Security::class) + ->set('current_password', 'password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + $response->assertHasNoErrors(); + + $this->assertTrue(Hash::check('new-password', $user->refresh()->password)); + } + + public function test_correct_password_must_be_provided_to_update_password(): void + { + $user = User::factory()->create([ + 'password' => Hash::make('password'), + ]); + + $this->actingAs($user); + + $response = Livewire::test(Security::class) + ->set('current_password', 'wrong-password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + $response->assertHasErrors(['current_password']); + } +} diff --git a/sk-klinik.my.id/tests/TestCase.php b/sk-klinik.my.id/tests/TestCase.php new file mode 100644 index 0000000..3399054 --- /dev/null +++ b/sk-klinik.my.id/tests/TestCase.php @@ -0,0 +1,16 @@ +markTestSkipped($message ?? "Fortify feature [{$feature}] is not enabled."); + } + } +} diff --git a/sk-klinik.my.id/tests/Unit/ExampleTest.php b/sk-klinik.my.id/tests/Unit/ExampleTest.php new file mode 100644 index 0000000..e93a27f --- /dev/null +++ b/sk-klinik.my.id/tests/Unit/ExampleTest.php @@ -0,0 +1,16 @@ +assertTrue(true); + } +} diff --git a/sk-klinik.my.id/vite.config.js b/sk-klinik.my.id/vite.config.js new file mode 100644 index 0000000..f65249e --- /dev/null +++ b/sk-klinik.my.id/vite.config.js @@ -0,0 +1,21 @@ +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(), + ], + server: { + cors: true, + watch: { + ignored: ['**/storage/framework/views/**'], + }, + }, +});