Mercurial > borealpoint
changeset 2:90296614b7e2 default tip
Adding in the base for the clients table
| author | luka |
|---|---|
| date | Thu, 28 Aug 2025 20:55:40 -0400 |
| parents | 8971e685366b |
| children | |
| files | app/Http/Controllers/ClientController.php app/Http/Requests/Client/FilterClientRequest.php app/Http/Requests/Client/StoreClientRequest.php app/Http/Requests/Client/UpdateClientRequest.php app/Models/Client.php database/migrations/2025_08_29_004806_create_clients_table.php resources/views/clients/create_edit.blade.php resources/views/clients/index.blade.php resources/views/clients/show.blade.php routes/resources/Client.php |
| diffstat | 10 files changed, 608 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/Http/Controllers/ClientController.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,129 @@ +<?php + +namespace App\Http\Controllers; + +use App\Http\Requests\Client\FilterClientRequest; +use App\Http\Requests\Client\StoreClientRequest; +use App\Http\Requests\Client\UpdateClientRequest; +use App\Models\Client; + +class ClientController extends Controller +{ + /** + * Display a listing of the resource. + * + * @return \Illuminate\View\View + */ + public function index(FilterClientRequest $request) + { + $validated = $request->validated(); + $data = []; + $data['items'] = Client::get_data($validated); + $data = array_merge($data, Client::load_index()); + + return view('clients.index', $data); + } + + public function get_data() + { + $data = []; + $data['records'] = Client::get_data([]); + $data['total_records'] = count($data['records']); + + return $data; + } + + /** + * Show the form for creating a new resource. + * + * @return \Illuminate\View\View + */ + public function create() + { + $data = []; + $data = array_merge($data, Client::load_create()); + + return view('clients.create_edit', $data); + } + + /** + * Store a newly created resource in storage. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function store(StoreClientRequest $request) + { + $validated = $request->validated(); + + Client::create($validated); + + return redirect()->route('clients.index'); + } + + /** + * Display the specified resource. + * + * @return \Illuminate\View\View + */ + public function show(Client $client) + { + $data = []; + $data['item'] = $client; + $data['fields'] = (new Client)->getFillable(); + + return view('clients.show', $data); + } + + /** + * Returns the resource in JSON format. + * + * @param ModelType $modelVariable + * @return string + */ + public function load(Client $client) + { + return $client->toJson(); + } + + /** + * Show the form for editing the specified resource. + * + * @return \Illuminate\View\View + */ + public function edit(Client $client) + { + $data = []; + $data['item'] = $client; + + // Load data for relationships + $data = array_merge($data, Client::load_edit()); + + return view('clients.create_edit', $data); + } + + /** + * Update the specified resource in storage. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function update(UpdateClientRequest $request, Client $client) + { + $validated = $request->validated(); + + $client->update($validated); + + return redirect()->route('clients.index'); + } + + /** + * Remove the specified resource from storage. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(Client $client) + { + $client->delete(); + + return redirect()->route('clients.index'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/Http/Requests/Client/FilterClientRequest.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,33 @@ +<?php + +namespace App\Http\Requests\Client; + +use Illuminate\Foundation\Http\FormRequest; + +class FilterClientRequest extends FormRequest +{ + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string> + */ + public function rules(): array + { + return [ + 'name' => 'nullable', + 'email' => 'nullable', + 'phone_number' => 'nullable', + 'address' => 'nullable', + 'notes' => 'nullable', + + ]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/Http/Requests/Client/StoreClientRequest.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,33 @@ +<?php + +namespace App\Http\Requests\Client; + +use Illuminate\Foundation\Http\FormRequest; + +class StoreClientRequest extends FormRequest +{ + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string> + */ + public function rules(): array + { + return [ + 'name' => 'nullable', + 'email' => 'nullable', + 'phone_number' => 'nullable', + 'address' => 'nullable', + 'notes' => 'nullable', + + ]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/Http/Requests/Client/UpdateClientRequest.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,33 @@ +<?php + +namespace App\Http\Requests\Client; + +use Illuminate\Foundation\Http\FormRequest; + +class UpdateClientRequest extends FormRequest +{ + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string> + */ + public function rules(): array + { + return [ + 'name' => 'nullable', + 'email' => 'nullable', + 'phone_number' => 'nullable', + 'address' => 'nullable', + 'notes' => 'nullable', + + ]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/Models/Client.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,126 @@ +<?php + +namespace App\Models; + +use Illuminate\Database\Eloquent\SoftDeletes; +use Wizard\Framework\Models\BaseModel; + +class Client extends BaseModel +{ + // use HasFactory; + use SoftDeletes; + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'clients'; + + /** + * The model's default values for attributes. + * + * @var array + */ + protected $attributes = [ + // {{ atributeInsertPoint }} + ]; + + protected $casts = [ + + ]; + + protected $fillable = [ + 'name', + 'email', + 'phone_number', + 'address', + 'notes', + + ]; + + protected $default_relations = [ + + ]; + + protected static $filters = [ + 'name' => [ + 'column_name' => 'name', + 'table' => 'clients', + 'display' => 'Name', + 'type' => 'value', + ], + 'email' => [ + 'column_name' => 'email', + 'table' => 'clients', + 'display' => 'Email', + 'type' => 'value', + ], + 'phone_number' => [ + 'column_name' => 'phone_number', + 'table' => 'clients', + 'display' => 'Phone Number', + 'type' => 'value', + ], + 'address' => [ + 'column_name' => 'address', + 'table' => 'clients', + 'display' => 'Address', + 'type' => 'value', + ], + 'notes' => [ + 'column_name' => 'notes', + 'table' => 'clients', + 'display' => 'Notes', + 'type' => 'value', + ], + + ]; + + public static function get_filters() + { + return static::filters; + } + + // relations + + // BelongsTo + + // HasMany + + // HasManyThrough + + /** + * Load the default relations for the model. + * + * @return $this + */ + public function load_relations() + { + foreach ($this->default_relations as $relation) { + $this->load($relation); + } + + return $this; + } + + /** + * Retrieve a query builder instance with default relations loaded. + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public static function data_query() + { + return parent::data_query(); + } + + /** + * Retrieve a query builder instance with default relations loaded. + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public static function get_data(array $validated = []) + { + return parent::get_data($validated); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/database/migrations/2025_08_29_004806_create_clients_table.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,31 @@ +<?php + +use Illuminate\Database\Migrations\Migration; +use Wizard\Framework\Database\MyBlueprint as Blueprint; +use Wizard\Framework\Database\MySchema as Schema; + +return new class extends Migration +{ + /** + * Run the migrations. + */ + public function up(): void + { + Schema::create('clients', function (Blueprint $table) { + $table->baseColumns(); + $table->string('name'); + $table->string('email')->nullable(); + $table->string('phone_number')->nullable(); + $table->string('address')->nullable(); + $table->text('notes')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('clients'); + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/resources/views/clients/create_edit.blade.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,64 @@ +<x-app-layout> + <x-slot name="header"> + <h2 class="fw-semibold fs-4 text-dark"> + {{ isset($item) ? 'Edit' : 'Create' }} {{ ucfirst('client') }} + </h2> + </x-slot> + + <div class="py-5"> + <div class="container"> + <div class="bg-white shadow-sm rounded p-4"> + <form method="POST" action="{{ isset($item) ? route('clients.update', $item) : route('clients.store') }}"> + @csrf + @if (isset($item)) + @method('PUT') + @endif + + <x-form.text + name="name" + label="Name" + :value="request('name', $item?->name ?? '')" + :required="true" +></x-form.text> + + <x-form.text + name="email" + label="Email" + :value="request('email', $item?->email ?? '')" + :required="false" +></x-form.text> + + <x-form.text + name="phone_number" + label="Phone Number" + :value="request('phone_number', $item?->phone_number ?? '')" + :required="false" +></x-form.text> + + <x-form.text + name="address" + label="Address" + :value="request('address', $item?->address ?? '')" + :required="false" +></x-form.text> + + <x-form.textarea + name="notes" + label="Notes" + :value="request('notes', $item?->notes ?? '')" + :required="false" +></x-form.textarea> + + + <div class="d-flex justify-content-end"> + <a href="{{ route('clients.index') }}" + class="btn btn-secondary me-2">Back</a> + <button type="submit" class="btn btn-primary"> + {{ isset($item) ? 'Update' : 'Create' }} + </button> + </div> + </form> + </div> + </div> + </div> +</x-app-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/resources/views/clients/index.blade.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,112 @@ +<x-app-layout> + <x-slot name="header"> + <h2 class="fw-semibold fs-4 text-dark"> + All {{ Str::plural(ucfirst('client')) }} + </h2> + </x-slot> + + <div class="py-5"> + <div class="container"> + <div class="bg-white shadow-sm rounded p-4"> + <div class="d-flex align-items-center justify-content-between mb-3"> + <a href="{{ route('clients.create') }}" class="btn btn-primary"> + + New {{ ucfirst('client') }} + </a> + </div> + <div id="my-table"></div> + </div> + </div> + </div> + + @include('includes.ServerTable') + @pushOnce('scripts') + <meta name="csrf-token" content="{{ csrf_token() }}"> + @endpushOnce + <script> + document.addEventListener('DOMContentLoaded', function() { + const el = document.getElementById('my-table'); + if (el) { + new ServerTable(el, { + endpoint: '/clients/get_data', + columns: [ + { + name: 'name', + label: 'Name', + class: 'p-2' +}, + + { + name: 'email', + label: 'Email', + class: 'p-2' +}, + + { + name: 'phone_number', + label: 'Phone Number', + class: 'p-2' +}, + + { + name: 'address', + label: 'Address', + class: 'p-2' +}, + + { + name: 'notes', + label: 'Notes', + class: 'p-2' +}, + + { + name: 'actions', + label: ' ', + render: function(row, col, i) { + let actions = ` + <div class="d-flex gap-2"> + <a href="{{ route('clients.show', 'PLACEHOLDER') }}" class="text-primary">View</a> + <a href="{{ route('clients.edit', 'PLACEHOLDER') }}" class="text-warning">Edit</a> + <form action="{{ route('clients.destroy', 'PLACEHOLDER') }}" method="POST" + class="d-inline"> + @csrf + @method('DELETE') + <button type="submit" class="btn btn-link text-danger p-0" + onclick="return confirm('Delete?')">Delete</button> + </form> + </div> + `; + actions = actions.split('PLACEHOLDER').join(row.id); + return actions; + } + } + ], + pageSize: 10, + initialSort: [{ + col: 'created_at', + dir: 'desc' + }], + headers: { + 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute( + 'content') + }, + skeleton: ` + <div class="st-table-container"> + <table class="table table-hover"> + <thead> + </thead> + <tbody> + <!-- Data rows will go here --> + </tbody> + </table> + <div class="st-controls"> + <span class="st-pagination"></span> + <span class="st-status"></span> + </div> + </div> + ` + }); + } + }); + </script> +</x-app-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/resources/views/clients/show.blade.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,26 @@ +<x-app-layout> + <x-slot name="header"> + <h2 class="fw-semibold fs-4 text-dark"> + {{ ucfirst('client') }} Details + </h2> + </x-slot> + + <div class="py-5"> + <div class="container"> + <div class="bg-white shadow-sm rounded p-4"> + <div class="mb-3"> + @foreach($fields as $field) + <div class="mb-2"> + <span class="fw-semibold">{{ ucfirst($field) }}:</span> + <span class="ms-2">{{ $item->$field }}</span> + </div> + @endforeach + </div> + <div class="d-flex justify-content-end mt-4"> + <a href="{{ route('clients.edit', $item) }}" class="me-2 btn btn-warning text-white">Edit</a> + <a href="{{ route('clients.index') }}" class="btn btn-secondary">Back</a> + </div> + </div> + </div> + </div> +</x-app-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/routes/resources/Client.php Thu Aug 28 20:55:40 2025 -0400 @@ -0,0 +1,21 @@ +<?php + +use App\Http\Controllers\ClientController; +use Illuminate\Support\Facades\Route; + +Route::controller(ClientController::class) + ->middleware(['web', 'auth']) + ->prefix('clients') + ->as('clients.') + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::post('/get_data', 'get_data')->name('get_data'); + Route::get('/create', 'create')->name('create'); + Route::get('/{client}/edit', 'edit')->name('edit'); + Route::get('/{client}', 'show')->name('show'); + Route::get('/{client}/load', 'load')->name('load'); + + Route::post('/store', 'store')->name('store'); + Route::put('/udpate/{client}', 'update')->name('update'); + Route::delete('/destroy/{client}', 'destroy')->name('destroy'); + });
