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');
+    });