Skip to content

Commit

Permalink
Merge pull request #290 from liberu-billing/sweep/Add-Client-Manageme…
Browse files Browse the repository at this point in the history
…nt-Functionality-to-Billing-Application

Add Client Management Functionality to Billing Application
  • Loading branch information
curtisdelicata authored Dec 24, 2024
2 parents 3e0e263 + 1453f77 commit 2c7138f
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 0 deletions.
79 changes: 79 additions & 0 deletions app/Http/Controllers/ClientController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@


<?php

namespace App\Http\Controllers;

use App\Models\Client;
use Illuminate\Http\Request;

class ClientController extends Controller
{
public function index(Request $request)
{
$query = Client::query();

if ($request->search) {
$query->where(function($q) use ($request) {
$q->where('name', 'like', "%{$request->search}%")
->orWhere('email', 'like', "%{$request->search}%")
->orWhere('company', 'like', "%{$request->search}%");
});
}

if ($request->status) {
$query->where('status', $request->status);
}

$clients = $query->paginate(10);
return view('clients.index', compact('clients'));
}

public function create()
{
return view('clients.create');
}

public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:clients',
'phone' => 'nullable|string|max:20',
'company' => 'nullable|string|max:255',
'address' => 'nullable|string',
'notes' => 'nullable|string',
'status' => 'required|in:active,inactive',
]);

Client::create($validated);
return redirect()->route('clients.index')->with('success', 'Client created successfully');
}

public function edit(Client $client)
{
return view('clients.edit', compact('client'));
}

public function update(Request $request, Client $client)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:clients,email,'.$client->id,
'phone' => 'nullable|string|max:20',
'company' => 'nullable|string|max:255',
'address' => 'nullable|string',
'notes' => 'nullable|string',
'status' => 'required|in:active,inactive',
]);

$client->update($validated);
return redirect()->route('clients.index')->with('success', 'Client updated successfully');
}

public function destroy(Client $client)
{
$client->delete();
return redirect()->route('clients.index')->with('success', 'Client deleted successfully');
}
}
28 changes: 28 additions & 0 deletions app/Models/Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@


<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Client extends Model
{
use HasFactory;

protected $fillable = [
'name',
'email',
'phone',
'company',
'address',
'notes',
'status'
];

protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
}
30 changes: 30 additions & 0 deletions database/migrations/2024_01_20_000000_create_clients_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@


<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('clients', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('phone')->nullable();
$table->string('company')->nullable();
$table->text('address')->nullable();
$table->text('notes')->nullable();
$table->enum('status', ['active', 'inactive'])->default('active');
$table->timestamps();
});
}

public function down(): void
{
Schema::dropIfExists('clients');
}
};
77 changes: 77 additions & 0 deletions resources/views/clients/index.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@


<x-app-layout>
<x-slot name="header">
<div class="flex justify-between">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Clients') }}
</h2>
<a href="{{ route('clients.create') }}" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Add Client
</a>
</div>
</x-slot>

<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
<!-- Search and Filter -->
<form method="GET" class="mb-6">
<div class="flex gap-4">
<input type="text" name="search" value="{{ request('search') }}"
class="border rounded px-4 py-2 w-full"
placeholder="Search clients...">
<select name="status" class="border rounded px-4 py-2">
<option value="">All Status</option>
<option value="active" {{ request('status') === 'active' ? 'selected' : '' }}>Active</option>
<option value="inactive" {{ request('status') === 'inactive' ? 'selected' : '' }}>Inactive</option>
</select>
<button type="submit" class="bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
Search
</button>
</div>
</form>

<!-- Clients Table -->
<table class="min-w-full">
<thead>
<tr>
<th class="px-6 py-3 border-b">Name</th>
<th class="px-6 py-3 border-b">Email</th>
<th class="px-6 py-3 border-b">Company</th>
<th class="px-6 py-3 border-b">Status</th>
<th class="px-6 py-3 border-b">Actions</th>
</tr>
</thead>
<tbody>
@foreach($clients as $client)
<tr>
<td class="px-6 py-4 border-b">{{ $client->name }}</td>
<td class="px-6 py-4 border-b">{{ $client->email }}</td>
<td class="px-6 py-4 border-b">{{ $client->company }}</td>
<td class="px-6 py-4 border-b">
<span class="px-2 py-1 rounded {{ $client->status === 'active' ? 'bg-green-200' : 'bg-red-200' }}">
{{ $client->status }}
</span>
</td>
<td class="px-6 py-4 border-b">
<a href="{{ route('clients.edit', $client) }}" class="text-blue-600 hover:text-blue-900">Edit</a>
<form action="{{ route('clients.destroy', $client) }}" method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-900 ml-4"
onclick="return confirm('Are you sure?')">Delete</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>

<div class="mt-4">
{{ $clients->links() }}
</div>
</div>
</div>
</div>
</x-app-layout>
5 changes: 5 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Support\Facades\Route;
use Laravel\Jetstream\Http\Controllers\TeamInvitationController;
use App\Http\Controllers\ClientController;

/*
|--------------------------------------------------------------------------
Expand All @@ -17,6 +18,10 @@

Route::get('/', fn () => view('welcome'));

Route::middleware(['auth:sanctum', 'verified'])->group(function () {
Route::resource('clients', ClientController::class);
});

// Route::redirect('/login', '/app/login')->name('login');

// Route::redirect('/register', '/app/register')->name('register');
Expand Down

0 comments on commit 2c7138f

Please sign in to comment.