From aa3289bd56d8816549e7b5d08feb96caecde8924 Mon Sep 17 00:00:00 2001 From: Daeng Deni Mardaeni Date: Thu, 8 Aug 2024 22:42:10 +0700 Subject: [PATCH] Feature #1 : Provinces --- app/Exports/ProvincesExport.php | 41 +++++ app/Http/Controllers/ProvincesController.php | 133 ++++++++++++++ app/Http/Requests/ProvinceRequest.php | 33 ++++ app/Models/Base.php | 50 +++++ app/Models/Province.php | 22 +++ app/Providers/LocationServiceProvider.php | 4 + ...24_08_08_144058_create_provinces_table.php | 33 ++++ database/seeders/LocationDatabaseSeeder.php | 4 +- database/seeders/ProvinceSeeder.php | 60 ++++++ module.json | 2 +- resources/views/index.blade.php | 7 - resources/views/layouts/master.blade.php | 29 --- resources/views/provinces/create.blade.php | 58 ++++++ resources/views/provinces/index.blade.php | 172 ++++++++++++++++++ routes/breadcrumbs.php | 27 +++ routes/web.php | 35 ++-- 16 files changed, 659 insertions(+), 51 deletions(-) create mode 100644 app/Exports/ProvincesExport.php create mode 100644 app/Http/Controllers/ProvincesController.php create mode 100644 app/Http/Requests/ProvinceRequest.php create mode 100644 app/Models/Base.php create mode 100644 app/Models/Province.php create mode 100644 database/migrations/2024_08_08_144058_create_provinces_table.php create mode 100644 database/seeders/ProvinceSeeder.php delete mode 100644 resources/views/index.blade.php delete mode 100644 resources/views/layouts/master.blade.php create mode 100644 resources/views/provinces/create.blade.php create mode 100644 resources/views/provinces/index.blade.php create mode 100644 routes/breadcrumbs.php diff --git a/app/Exports/ProvincesExport.php b/app/Exports/ProvincesExport.php new file mode 100644 index 0000000..1fd5970 --- /dev/null +++ b/app/Exports/ProvincesExport.php @@ -0,0 +1,41 @@ +id, + $row->code, + $row->name, + $row->created_at + ]; + } + public function headings(): array{ + return [ + 'ID', + 'Code', + 'Name', + 'Created At' + ]; + } + + public function columnFormats(): array{ + return [ + 'A' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER, + 'C' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME + ]; + } +} diff --git a/app/Http/Controllers/ProvincesController.php b/app/Http/Controllers/ProvincesController.php new file mode 100644 index 0000000..745d6ed --- /dev/null +++ b/app/Http/Controllers/ProvincesController.php @@ -0,0 +1,133 @@ +validated(); + + if($validate){ + try{ + // Save to database + $province = Province::create($validate); + return redirect()->route('locations.provinces.index')->with('success', 'Province created successfully'); + } catch (\Exception $e){ + return redirect()->route('locations.provinces.create')->with('error', 'Failed to create province'); + } + } + } + + public function edit($id){ + $province = Province::find($id); + return view('location::provinces.create', compact('province')); + } + + public function update(ProvinceRequest $request, $id){ + $validate = $request->validated(); + + if($validate){ + try{ + // Update in database + $province = Province::find($id); + $province->update($validate); + return redirect()->route('locations.provinces.index')->with('success', 'Province updated successfully'); + } catch (\Exception $e){ + return redirect()->route('locations.provinces.edit', $id)->with('error', 'Failed to update province'); + } + } + } + + public function destroy($id){ + try{ + // Delete from database + $province = Province::find($id); + $province->delete(); + + echo json_encode(['success' => true, 'message' => 'Province deleted successfully']); + } catch (\Exception $e){ + echo json_encode(['success' => false, 'message' => 'Failed to delete province']); + } + } + + public function dataForDatatables(Request $request){ + if (is_null($this->user) || !$this->user->can('provinces.view')) { + //abort(403, 'Sorry! You are not allowed to view users.'); + } + + // Retrieve data from the database + $query = Province::query(); + + // Apply search filter if provided + if ($request->has('search') && !empty($request->get('search'))) { + $search = $request->get('search'); + $query->where(function ($q) use ($search) { + $q->where('name', 'LIKE', "%$search%"); + }); + } + + // Apply sorting if provided + if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) { + $order = $request->get('sortOrder'); + $column = $request->get('sortField'); + $query->orderBy($column, $order); + } + + // Get the total count of records + $totalRecords = $query->count(); + + // Apply pagination if provided + if ($request->has('page') && $request->has('size')) { + $page = $request->get('page'); + $size = $request->get('size'); + $offset = ($page - 1) * $size; // Calculate the offset + + $query->skip($offset)->take($size); + } + + // Get the filtered count of records + $filteredRecords = $query->count(); + + // Get the data for the current page + $roles = $query->get(); + + // Calculate the page count + $pageCount = ceil($totalRecords/$request->get('size')); + + // Calculate the current page number + $currentPage = 0 + 1; + + // Return the response data as a JSON object + return response()->json([ + 'draw' => $request->get('draw'), + 'recordsTotal' => $totalRecords, + 'recordsFiltered' => $filteredRecords, + 'pageCount' => $pageCount, + 'page' => $currentPage, + 'totalCount' => $totalRecords, + 'data' => $roles, + ]); + } + + public function export() + { + return Excel::download(new ProvincesExport, 'provinces.xlsx'); + } +} diff --git a/app/Http/Requests/ProvinceRequest.php b/app/Http/Requests/ProvinceRequest.php new file mode 100644 index 0000000..28dd0c0 --- /dev/null +++ b/app/Http/Requests/ProvinceRequest.php @@ -0,0 +1,33 @@ +method() === 'PUT') { + $rules['code'] = 'required|string|max:4|unique:provinces,code,' . $this->id; + $rules['name'] = 'required|string|max:2554|unique:provinces,name,' . $this->id; + } else { + $rules['code'] = 'required|string|max:4|unique:provinces,code'; + $rules['name'] = 'required|string|max:2554|unique:provinces,name'; + } + + return $rules; + } + + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } +} diff --git a/app/Models/Base.php b/app/Models/Base.php new file mode 100644 index 0000000..1f3d417 --- /dev/null +++ b/app/Models/Base.php @@ -0,0 +1,50 @@ +connection = $module->database; + } + + /** + * Retrieves the activity log options for the User Management. + * + * @return LogOptions The activity log options. + */ + public function getActivitylogOptions() + : LogOptions + { + return LogOptions::defaults()->logAll()->useLogName('Locations : '); + } + } diff --git a/app/Models/Province.php b/app/Models/Province.php new file mode 100644 index 0000000..8eb7888 --- /dev/null +++ b/app/Models/Province.php @@ -0,0 +1,22 @@ +hasMany(City::class, 'province_code', 'code'); + } + } + + diff --git a/app/Providers/LocationServiceProvider.php b/app/Providers/LocationServiceProvider.php index 1186986..6400867 100644 --- a/app/Providers/LocationServiceProvider.php +++ b/app/Providers/LocationServiceProvider.php @@ -22,6 +22,10 @@ class LocationServiceProvider extends ServiceProvider $this->registerConfig(); $this->registerViews(); $this->loadMigrationsFrom(module_path($this->moduleName, 'database/migrations')); + + if (class_exists('Breadcrumbs')) { + require __DIR__ . '/../../routes/breadcrumbs.php'; + } } /** diff --git a/database/migrations/2024_08_08_144058_create_provinces_table.php b/database/migrations/2024_08_08_144058_create_provinces_table.php new file mode 100644 index 0000000..eeee2cf --- /dev/null +++ b/database/migrations/2024_08_08_144058_create_provinces_table.php @@ -0,0 +1,33 @@ +id(); + $table->string('code'); + $table->string('name'); + $table->timestamps(); + $table->softDeletes(); + $table->uuid('created_by')->nullable(); + $table->uuid('updated_by')->nullable(); + $table->uuid('deleted_by')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('provinces'); + } +}; diff --git a/database/seeders/LocationDatabaseSeeder.php b/database/seeders/LocationDatabaseSeeder.php index c0e8dde..ae2ec13 100644 --- a/database/seeders/LocationDatabaseSeeder.php +++ b/database/seeders/LocationDatabaseSeeder.php @@ -11,6 +11,8 @@ class LocationDatabaseSeeder extends Seeder */ public function run(): void { - // $this->call([]); + $this->call([ + ProvinceSeeder::class + ]); } } diff --git a/database/seeders/ProvinceSeeder.php b/database/seeders/ProvinceSeeder.php new file mode 100644 index 0000000..b25b372 --- /dev/null +++ b/database/seeders/ProvinceSeeder.php @@ -0,0 +1,60 @@ + '11', 'name' => 'Aceh'], + ['code' => '12', 'name' => 'Sumatera Utara'], + ['code' => '13', 'name' => 'Sumatera Barat'], + ['code' => '14', 'name' => 'Riau'], + ['code' => '15', 'name' => 'Jambi'], + ['code' => '16', 'name' => 'Sumatera Selatan'], + ['code' => '17', 'name' => 'Bengkulu'], + ['code' => '18', 'name' => 'Lampung'], + ['code' => '19', 'name' => 'Kepulauan Bangka Belitung'], + ['code' => '21', 'name' => 'Kepulauan Riau'], + ['code' => '31', 'name' => 'Jakarta'], + ['code' => '32', 'name' => 'Jawa Barat'], + ['code' => '33', 'name' => 'Jawa Tengah'], + ['code' => '34', 'name' => 'Yogyakarta'], + ['code' => '35', 'name' => 'Jawa Timur'], + ['code' => '36', 'name' => 'Banten'], + ['code' => '51', 'name' => 'Bali'], + ['code' => '52', 'name' => 'Nusa Tenggara Barat'], + ['code' => '53', 'name' => 'Nusa Tenggara Timur'], + ['code' => '61', 'name' => 'Kalimantan Barat'], + ['code' => '62', 'name' => 'Kalimantan Tengah'], + ['code' => '63', 'name' => 'Kalimantan Selatan'], + ['code' => '64', 'name' => 'Kalimantan Timur'], + ['code' => '65', 'name' => 'Kalimantan Utara'], + ['code' => '71', 'name' => 'Sulawesi Utara'], + ['code' => '72', 'name' => 'Sulawesi Tengah'], + ['code' => '73', 'name' => 'Sulawesi Selatan'], + ['code' => '74', 'name' => 'Sulawesi Tenggara'], + ['code' => '75', 'name' => 'Gorontalo'], + ['code' => '76', 'name' => 'Sulawesi Barat'], + ['code' => '81', 'name' => 'Maluku'], + ['code' => '82', 'name' => 'Maluku Utara'], + ['code' => '91', 'name' => 'Papua'], + ['code' => '92', 'name' => 'Papua Barat'], + ['code' => '92.1', 'name' => 'Papua Barat Daya'], + ['code' => '93', 'name' => 'Papua Tengah'], + ['code' => '94', 'name' => 'Papua Selatan'], + ['code' => '95', 'name' => 'Papua Pegunungan'], + ]; + + foreach ($provinces as $province) { + Province::create($province); + } + } +} diff --git a/module.json b/module.json index d720b17..c662a7b 100644 --- a/module.json +++ b/module.json @@ -23,7 +23,7 @@ "sub": [ { "title": "Provinces", - "path": "", + "path": "locations.provinces", "classes": "", "attributes": [], "permission": "", diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php deleted file mode 100644 index 143a322..0000000 --- a/resources/views/index.blade.php +++ /dev/null @@ -1,7 +0,0 @@ -@extends('location::layouts.master') - -@section('content') -

Hello World

- -

Module: {!! config('location.name') !!}

-@endsection diff --git a/resources/views/layouts/master.blade.php b/resources/views/layouts/master.blade.php deleted file mode 100644 index 5137ea5..0000000 --- a/resources/views/layouts/master.blade.php +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - Location Module - {{ config('app.name', 'Laravel') }} - - - - - - - - - - {{-- Vite CSS --}} - {{-- {{ module_vite('build-location', 'resources/assets/sass/app.scss') }} --}} - - - - @yield('content') - - {{-- Vite JS --}} - {{-- {{ module_vite('build-location', 'resources/assets/js/app.js') }} --}} - diff --git a/resources/views/provinces/create.blade.php b/resources/views/provinces/create.blade.php new file mode 100644 index 0000000..e0b4188 --- /dev/null +++ b/resources/views/provinces/create.blade.php @@ -0,0 +1,58 @@ +@extends('layouts.main') + +@section('breadcrumbs') + {{ Breadcrumbs::render(request()->route()->getName()) }} +@endsection + +@section('content') +
+ @if(isset($province->id)) +
+ + @method('PUT') + @else + + @endif + @csrf +
+
+

+ {{ isset($province->id) ? 'Edit' : 'Add' }} Province +

+
+ Back +
+
+
+
+ +
+ + @error('code') + {{ $message }} + @enderror +
+
+
+ +
+ + @error('name') + {{ $message }} + @enderror +
+
+
+ +
+
+
+
+
+@endsection diff --git a/resources/views/provinces/index.blade.php b/resources/views/provinces/index.blade.php new file mode 100644 index 0000000..cbf0d30 --- /dev/null +++ b/resources/views/provinces/index.blade.php @@ -0,0 +1,172 @@ +@extends('layouts.main') + +@section('breadcrumbs') + {{ Breadcrumbs::render('locations.provinces') }} +@endsection + +@section('content') +
+
+
+
+

+ List of Provinces +

+
+
+ +
+
+ + + +
+ Export to Excel + Add Province +
+
+
+
+
+ + + + + + + + + +
+ + + Code + + + Province + + Action
+
+ +
+
+
+
+@endsection + +@push('scripts') + + + +@endpush + diff --git a/routes/breadcrumbs.php b/routes/breadcrumbs.php new file mode 100644 index 0000000..127d715 --- /dev/null +++ b/routes/breadcrumbs.php @@ -0,0 +1,27 @@ +push('Locations'); + }); + + // Provinces + Breadcrumbs::for('locations.provinces', function (BreadcrumbTrail $trail) { + $trail->parent('locations'); + $trail->push('Provinces', route('locations.provinces.index')); + }); + + Breadcrumbs::for('locations.provinces.create', function (BreadcrumbTrail $trail) { + $trail->parent('locations.provinces'); + $trail->push('Create Province', route('locations.provinces.create')); + }); + + Breadcrumbs::for('locations.provinces.edit', function (BreadcrumbTrail $trail) { + $trail->parent('locations.provinces'); + $trail->push('Edit Province'); + }); + + // Districts diff --git a/routes/web.php b/routes/web.php index e0631d8..bd22cb7 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,18 +2,27 @@ use Illuminate\Support\Facades\Route; use Modules\Location\Http\Controllers\LocationController; + use Modules\Location\Http\Controllers\ProvincesController; -/* -|-------------------------------------------------------------------------- -| Web Routes -|-------------------------------------------------------------------------- -| -| Here is where you can register web routes for your application. These -| routes are loaded by the RouteServiceProvider within a group which -| contains the "web" middleware group. Now create something great! -| -*/ + /* + |-------------------------------------------------------------------------- + | Web Routes + |-------------------------------------------------------------------------- + | + | Here is where you can register web routes for your application. These + | routes are loaded by the RouteServiceProvider within a group which + | contains the "web" middleware group. Now create something great! + | + */ -Route::group([], function () { - Route::resource('location', LocationController::class)->names('location'); -}); + Route::middleware(['auth'])->group(function () { + Route::name('locations.')->prefix('locations')->group(function () { + Route::name('provinces.')->prefix('roles')->group(function () { + Route::get('restore/{id}', [ProvincesController::class, 'restore'])->name('restore'); + Route::get('datatables', [ProvincesController::class, 'dataForDatatables'])->name('datatables'); + Route::get('export', [ProvincesController ::class, 'export'])->name('export'); + }); + + Route::resource('provinces', ProvincesController::class); + }); + });