Clients CRUD
This commit is contained in:
parent
3f4dbbf5d4
commit
282ef63cf2
12
app/Enums/ProjectStatus.php
Normal file
12
app/Enums/ProjectStatus.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum ProjectStatus: string
|
||||||
|
{
|
||||||
|
case OPEN = 'open';
|
||||||
|
case IN_PROGRESS = 'in progress';
|
||||||
|
case BLOCKED = 'blocked';
|
||||||
|
case CANCELLED = 'cancelled';
|
||||||
|
case COMPLETED = 'completed';
|
||||||
|
}
|
||||||
50
app/Http/Controllers/ClientController.php
Normal file
50
app/Http/Controllers/ClientController.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use App\Http\Requests\StoreClientRequest;
|
||||||
|
use App\Http\Requests\UpdateClientRequest;
|
||||||
|
|
||||||
|
class ClientController extends Controller
|
||||||
|
{
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
$clients = Client::paginate(20);
|
||||||
|
|
||||||
|
return view('clients.index', compact('clients'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
return view('clients.create');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(StoreClientRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
Client::create($request->validated());
|
||||||
|
|
||||||
|
return redirect()->route('clients.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Client $client): View
|
||||||
|
{
|
||||||
|
return view('clients.edit', compact('client'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UpdateClientRequest $request, Client $client): RedirectResponse
|
||||||
|
{
|
||||||
|
$client->update($request->validated());
|
||||||
|
|
||||||
|
return redirect()->route('clients.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Client $client): RedirectResponse
|
||||||
|
{
|
||||||
|
$client->delete();
|
||||||
|
|
||||||
|
return redirect()->route('clients.index');
|
||||||
|
}
|
||||||
|
}
|
||||||
58
app/Http/Controllers/ProjectController.php
Normal file
58
app/Http/Controllers/ProjectController.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Project;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use App\Http\Requests\StoreProjectRequest;
|
||||||
|
use App\Http\Requests\UpdateProjectRequest;
|
||||||
|
|
||||||
|
class ProjectController extends Controller
|
||||||
|
{
|
||||||
|
public function index(): View
|
||||||
|
{
|
||||||
|
$projects = Project::with(['user', 'client'])->paginate(10);
|
||||||
|
|
||||||
|
return view('projects.index', compact('projects'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(): View
|
||||||
|
{
|
||||||
|
$users = User::select(['id', 'first_name', 'last_name'])->get();
|
||||||
|
$clients = Client::select(['id', 'company_name'])->get();
|
||||||
|
|
||||||
|
return view('projects.create', compact('users', 'clients'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(StoreProjectRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
Project::create($request->validated());
|
||||||
|
|
||||||
|
return redirect()->route('projects.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Project $project): View
|
||||||
|
{
|
||||||
|
$users = User::select(['id', 'first_name', 'last_name'])->get();
|
||||||
|
$clients = Client::select(['id', 'company_name'])->get();
|
||||||
|
|
||||||
|
return view('projects.edit', compact('project', 'users', 'clients'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UpdateProjectRequest $request, Project $project): RedirectResponse
|
||||||
|
{
|
||||||
|
$project->update($request->validated());
|
||||||
|
|
||||||
|
return redirect()->route('projects.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Project $project): RedirectResponse
|
||||||
|
{
|
||||||
|
$project->delete();
|
||||||
|
|
||||||
|
return redirect()->route('projects.index');
|
||||||
|
}
|
||||||
|
}
|
||||||
36
app/Http/Requests/StoreClientRequest.php
Normal file
36
app/Http/Requests/StoreClientRequest.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
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<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'contact_name' => ['required', 'string', 'max:255'],
|
||||||
|
'contact_email' => ['required', 'string', 'email', 'max:255', Rule::unique('clients')],
|
||||||
|
'contact_phone_number' => ['required'],
|
||||||
|
'company_name' => ['required'],
|
||||||
|
'company_address' => ['required'],
|
||||||
|
'company_city' => ['required', 'string'],
|
||||||
|
'company_zip' => ['required', 'integer'],
|
||||||
|
'company_vat' => ['required', 'numeric'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/Http/Requests/StoreProjectRequest.php
Normal file
35
app/Http/Requests/StoreProjectRequest.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Enums\ProjectStatus;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class StoreProjectRequest 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<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => ['required'],
|
||||||
|
'description' => ['required'],
|
||||||
|
'user_id' => ['required', Rule::exists('users', 'id')],
|
||||||
|
'client_id' => ['required', Rule::exists('clients', 'id')],
|
||||||
|
'deadline_at' => ['required', 'date'],
|
||||||
|
'status' => ['required', Rule::enum(ProjectStatus::class)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
36
app/Http/Requests/UpdateClientRequest.php
Normal file
36
app/Http/Requests/UpdateClientRequest.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
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<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'contact_name' => ['required', 'string', 'max:255'],
|
||||||
|
'contact_email' => ['required', 'string', 'email', 'max:255', Rule::unique('clients')->ignore($this->client)],
|
||||||
|
'contact_phone_number' => ['required'],
|
||||||
|
'company_name' => ['required'],
|
||||||
|
'company_address' => ['required'],
|
||||||
|
'company_city' => ['required', 'string'],
|
||||||
|
'company_zip' => ['required', 'integer'],
|
||||||
|
'company_vat' => ['required', 'numeric'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
35
app/Http/Requests/UpdateProjectRequest.php
Normal file
35
app/Http/Requests/UpdateProjectRequest.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Enums\ProjectStatus;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class UpdateProjectRequest 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<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => ['required'],
|
||||||
|
'description' => ['required'],
|
||||||
|
'user_id' => ['required', Rule::exists('users', 'id')],
|
||||||
|
'client_id' => ['required', Rule::exists('clients', 'id')],
|
||||||
|
'deadline_at' => ['required', 'date'],
|
||||||
|
'status' => ['required', Rule::enum(ProjectStatus::class)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
23
app/Models/Client.php
Normal file
23
app/Models/Client.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Client extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'contact_name',
|
||||||
|
'contact_email',
|
||||||
|
'contact_phone_number',
|
||||||
|
'company_name',
|
||||||
|
'company_address',
|
||||||
|
'company_city',
|
||||||
|
'company_zip',
|
||||||
|
'company_vat',
|
||||||
|
];
|
||||||
|
}
|
||||||
40
app/Models/Project.php
Normal file
40
app/Models/Project.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\ProjectStatus;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Project extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'title',
|
||||||
|
'description',
|
||||||
|
'user_id',
|
||||||
|
'client_id',
|
||||||
|
'deadline_at',
|
||||||
|
'status',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function client(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Client::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => ProjectStatus::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
database/factories/ClientFactory.php
Normal file
30
database/factories/ClientFactory.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Client>
|
||||||
|
*/
|
||||||
|
class ClientFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'contact_name' => fake()->name(),
|
||||||
|
'contact_email' => fake()->unique()->safeEmail(),
|
||||||
|
'contact_phone_number' => fake()->phoneNumber(),
|
||||||
|
'company_name' => fake()->company(),
|
||||||
|
'company_address' => fake()->address(),
|
||||||
|
'company_city' => fake()->city(),
|
||||||
|
'company_zip' => fake()->postcode(),
|
||||||
|
'company_vat' => fake()->unique()->numerify(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
34
database/factories/ProjectFactory.php
Normal file
34
database/factories/ProjectFactory.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Enums\ProjectStatus;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Project>
|
||||||
|
*/
|
||||||
|
class ProjectFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
$users = User::pluck('id');
|
||||||
|
$clients = Client::pluck('id');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'title' => fake()->sentence(3),
|
||||||
|
'description' => fake()->paragraph(),
|
||||||
|
'deadline_at' => now()->addDays(rand(1, 30))->format('Y-m-d'),
|
||||||
|
'status' => fake()->randomElement(ProjectStatus::cases())->value,
|
||||||
|
'user_id' => $users->random(),
|
||||||
|
'client_id' => $clients->random(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('clients', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('contact_name');
|
||||||
|
$table->string('contact_email')->unique();
|
||||||
|
$table->string('contact_phone_number');
|
||||||
|
$table->string('company_name');
|
||||||
|
$table->string('company_address');
|
||||||
|
$table->string('company_city');
|
||||||
|
$table->string('company_zip');
|
||||||
|
$table->integer('company_vat');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('clients');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('projects', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('title');
|
||||||
|
$table->text('description');
|
||||||
|
$table->foreignId('user_id')->constrained();
|
||||||
|
$table->foreignId('client_id')->constrained();
|
||||||
|
$table->date('deadline_at');
|
||||||
|
$table->string('status');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('projects');
|
||||||
|
}
|
||||||
|
};
|
||||||
18
database/seeders/ClientSeeder.php
Normal file
18
database/seeders/ClientSeeder.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class ClientSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
Client::factory(50)->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
use App\RoleEnum;
|
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
class DatabaseSeeder extends Seeder
|
class DatabaseSeeder extends Seeder
|
||||||
@ -14,14 +12,11 @@ class DatabaseSeeder extends Seeder
|
|||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
$this->call(RoleSeeder::class);
|
$this->call([
|
||||||
|
RoleSeeder::class,
|
||||||
User::factory(10)->create();
|
UserSeeder::class,
|
||||||
User::factory()->create([
|
ClientSeeder::class,
|
||||||
'first_name' => 'Admin',
|
ProjectSeeder::class,
|
||||||
'last_name' => 'Admin',
|
]);
|
||||||
'email' => 'admin@admin.com',
|
|
||||||
'password' => 'secret',
|
|
||||||
])->syncRoles([RoleEnum::ADMIN]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
database/seeders/ProjectSeeder.php
Normal file
18
database/seeders/ProjectSeeder.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Project;
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class ProjectSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
Project::factory(20)->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
25
database/seeders/UserSeeder.php
Normal file
25
database/seeders/UserSeeder.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\RoleEnum;
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class UserSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
User::factory(10)->create();
|
||||||
|
User::factory()->create([
|
||||||
|
'first_name' => 'Admin',
|
||||||
|
'last_name' => 'Admin',
|
||||||
|
'email' => 'admin@admin.com',
|
||||||
|
'password' => 'secret',
|
||||||
|
])->syncRoles([RoleEnum::ADMIN]);
|
||||||
|
}
|
||||||
|
}
|
||||||
100
resources/views/clients/create.blade.php
Normal file
100
resources/views/clients/create.blade.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||||
|
{{ __('Create Client') }}
|
||||||
|
</h2>
|
||||||
|
</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-sm sm:rounded-lg">
|
||||||
|
<div class="overflow-hidden overflow-x-auto p-6 bg-white border-b border-gray-200">
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('clients.store') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="divide-y-2 space-y-4">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold mb-4">Contact information</h3>
|
||||||
|
<!-- Name -->
|
||||||
|
<div>
|
||||||
|
<x-input-label for="contact_name" :value="__('Name')"/>
|
||||||
|
<x-text-input id="contact_name" class="block mt-1 w-full" type="text"
|
||||||
|
name="contact_name" :value="old('contact_name')" required/>
|
||||||
|
<x-input-error :messages="$errors->get('contact_name')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email Address -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="contact_email" :value="__('Email')"/>
|
||||||
|
<x-text-input id="contact_email" class="block mt-1 w-full" type="email"
|
||||||
|
name="contact_email" :value="old('contact_email')" required/>
|
||||||
|
<x-input-error :messages="$errors->get('contact_email')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Phone Number -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="contact_phone_number" :value="__('Phone number')"/>
|
||||||
|
<x-text-input id="contact_phone_number" class="block mt-1 w-full" type="text"
|
||||||
|
name="contact_phone_number" :value="old('contact_phone_number')"
|
||||||
|
required/>
|
||||||
|
<x-input-error :messages="$errors->get('contact_phone_number')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold my-4 mt-4">Company information</h3>
|
||||||
|
<!-- Company Name -->
|
||||||
|
<div>
|
||||||
|
<x-input-label for="company_name" :value="__('Company Name')"/>
|
||||||
|
<x-text-input id="company_name" class="block mt-1 w-full" type="text"
|
||||||
|
name="company_name" :value="old('company_name')" required/>
|
||||||
|
<x-input-error :messages="$errors->get('company_name')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company VAT -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_vat" :value="__('Company VAT')"/>
|
||||||
|
<x-text-input id="company_vat" class="block mt-1 w-full" type="text"
|
||||||
|
name="company_vat" :value="old('company_vat')" required/>
|
||||||
|
<x-input-error :messages="$errors->get('company_vat')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company Address -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_address" :value="__('Company address')"/>
|
||||||
|
<x-text-input id="company_address" class="block mt-1 w-full" type="text"
|
||||||
|
name="company_address" :value="old('company_address')" required/>
|
||||||
|
<x-input-error :messages="$errors->get('company_address')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company City -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_city" :value="__('Company city')"/>
|
||||||
|
<x-text-input id="company_city" class="block mt-1 w-full" type="text"
|
||||||
|
name="company_city" :value="old('company_city')" required/>
|
||||||
|
<x-input-error :messages="$errors->get('company_city')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company ZIP -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_zip" :value="__('Company zip')"/>
|
||||||
|
<x-text-input id="company_zip" class="block mt-1 w-full" type="text"
|
||||||
|
name="company_zip" :value="old('company_zip')" required/>
|
||||||
|
<x-input-error :messages="$errors->get('company_zip')" class="mt-2"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<x-primary-button class="mt-4">
|
||||||
|
{{ __('Save') }}
|
||||||
|
</x-primary-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-app-layout>
|
||||||
92
resources/views/clients/edit.blade.php
Normal file
92
resources/views/clients/edit.blade.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||||
|
{{ __('Edit Client') }}
|
||||||
|
</h2>
|
||||||
|
</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-sm sm:rounded-lg">
|
||||||
|
<div class="overflow-hidden overflow-x-auto p-6 bg-white border-b border-gray-200">
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('clients.update', $client) }}">
|
||||||
|
@method('PUT')
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="divide-y-2 space-y-4">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold mb-4">Contact information</h3>
|
||||||
|
<!-- Name -->
|
||||||
|
<div>
|
||||||
|
<x-input-label for="contact_name" :value="__('Name')" />
|
||||||
|
<x-text-input id="contact_name" class="block mt-1 w-full" type="text" name="contact_name" :value="old('contact_name', $client->contact_name)" required />
|
||||||
|
<x-input-error :messages="$errors->get('contact_name')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email Address -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="contact_email" :value="__('Email')" />
|
||||||
|
<x-text-input id="contact_email" class="block mt-1 w-full" type="email" name="contact_email" :value="old('contact_email', $client->contact_email)" required />
|
||||||
|
<x-input-error :messages="$errors->get('contact_email')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Phone Number -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="contact_phone_number" :value="__('Phone number')" />
|
||||||
|
<x-text-input id="contact_phone_number" class="block mt-1 w-full" type="text" name="contact_phone_number" :value="old('contact_phone_number', $client->contact_phone_number)" required />
|
||||||
|
<x-input-error :messages="$errors->get('contact_phone_number')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-semibold my-4 mt-4">Company information</h3>
|
||||||
|
<!-- Company Name -->
|
||||||
|
<div>
|
||||||
|
<x-input-label for="company_name" :value="__('Company Name')" />
|
||||||
|
<x-text-input id="company_name" class="block mt-1 w-full" type="text" name="company_name" :value="old('company_name', $client->company_name)" required />
|
||||||
|
<x-input-error :messages="$errors->get('company_name')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company VAT -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_vat" :value="__('Company VAT')" />
|
||||||
|
<x-text-input id="company_vat" class="block mt-1 w-full" type="text" name="company_vat" :value="old('company_vat', $client->company_vat)" required />
|
||||||
|
<x-input-error :messages="$errors->get('company_vat')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company Address -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_address" :value="__('Company address')" />
|
||||||
|
<x-text-input id="company_address" class="block mt-1 w-full" type="text" name="company_address" :value="old('company_address', $client->company_address)" required />
|
||||||
|
<x-input-error :messages="$errors->get('company_address')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company City -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_city" :value="__('Company city')" />
|
||||||
|
<x-text-input id="company_city" class="block mt-1 w-full" type="text" name="company_city" :value="old('company_city', $client->company_city)" required />
|
||||||
|
<x-input-error :messages="$errors->get('company_city')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Company ZIP -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="company_zip" :value="__('Company zip')" />
|
||||||
|
<x-text-input id="company_zip" class="block mt-1 w-full" type="text" name="company_zip" :value="old('company_zip', $client->company_zip)" required />
|
||||||
|
<x-input-error :messages="$errors->get('company_zip')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<x-primary-button class="mt-4">
|
||||||
|
{{ __('Save') }}
|
||||||
|
</x-primary-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-app-layout>
|
||||||
67
resources/views/clients/index.blade.php
Normal file
67
resources/views/clients/index.blade.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||||
|
{{ __('Clients') }}
|
||||||
|
</h2>
|
||||||
|
</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-sm sm:rounded-lg">
|
||||||
|
<div class="p-6 text-gray-900">
|
||||||
|
<a href="{{ route('clients.create') }}" class="underline">Add new client</a>
|
||||||
|
|
||||||
|
<table class="min-w-full divide-y divide-gray-200 border mt-4">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Company</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">VAT</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Address</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200 divide-solid">
|
||||||
|
@foreach($clients as $client)
|
||||||
|
<tr class="bg-white">
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $client->company_name }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $client->company_vat }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $client->company_address }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
<a href="{{ route('clients.edit', $client) }}" class="underline">Edit</a>
|
||||||
|
|
|
||||||
|
<form action="{{ route('clients.destroy', $client) }}"
|
||||||
|
method="POST"
|
||||||
|
onsubmit="return confirm('Are you sure?');"
|
||||||
|
class="inline-block">
|
||||||
|
@method('DELETE')
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="text-red-500 underline">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
{{ $clients->links() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-app-layout>
|
||||||
@ -20,6 +20,12 @@
|
|||||||
{{ __('Users') }}
|
{{ __('Users') }}
|
||||||
</x-nav-link>
|
</x-nav-link>
|
||||||
@endrole
|
@endrole
|
||||||
|
<x-nav-link :href="route('clients.index')" :active="request()->routeIs('clients.*')">
|
||||||
|
{{ __('Clients') }}
|
||||||
|
</x-nav-link>
|
||||||
|
<x-nav-link :href="route('projects.index')" :active="request()->routeIs('projects.*')">
|
||||||
|
{{ __('Projects') }}
|
||||||
|
</x-nav-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -80,6 +86,12 @@
|
|||||||
{{ __('Users') }}
|
{{ __('Users') }}
|
||||||
</x-responsive-nav-link>
|
</x-responsive-nav-link>
|
||||||
@endrole
|
@endrole
|
||||||
|
<x-responsive-nav-link :href="route('clients.index')" :active="request()->routeIs('clients.*')">
|
||||||
|
{{ __('Clients') }}
|
||||||
|
</x-responsive-nav-link>
|
||||||
|
<x-responsive-nav-link :href="route('projects.index')" :active="request()->routeIs('projects.*')">
|
||||||
|
{{ __('Projects') }}
|
||||||
|
</x-responsive-nav-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Responsive Settings Options -->
|
<!-- Responsive Settings Options -->
|
||||||
|
|||||||
81
resources/views/projects/create.blade.php
Normal file
81
resources/views/projects/create.blade.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||||
|
{{ __('Create Project') }}
|
||||||
|
</h2>
|
||||||
|
</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-sm sm:rounded-lg">
|
||||||
|
<div class="overflow-hidden overflow-x-auto p-6 bg-white border-b border-gray-200">
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('projects.store') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<div>
|
||||||
|
<x-input-label for="title" :value="__('Title')" />
|
||||||
|
<x-text-input id="title" class="block mt-1 w-full" type="text" name="title" :value="old('title')" required />
|
||||||
|
<x-input-error :messages="$errors->get('title')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="description" :value="__('Description')" />
|
||||||
|
<textarea id="description" class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="description" required>{{ old('description') }}</textarea>
|
||||||
|
<x-input-error :messages="$errors->get('description')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Deadline At -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="deadline_at" :value="__('Deadline')" />
|
||||||
|
<x-text-input id="deadline_at" class="block mt-1 w-full" type="date" name="deadline_at" min="{{ today()->format('Y-m-d') }}" :value="old('deadline_at')" required />
|
||||||
|
<x-input-error :messages="$errors->get('deadline_at')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Assigned User -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="user_id" :value="__('Assigned user')" />
|
||||||
|
<select class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="user_id" id="user_id">
|
||||||
|
@foreach($users as $user)
|
||||||
|
<option value="{{ $user->id }}"
|
||||||
|
@selected(old('user_id') == $user->id)>{{ $user->first_name . ' ' . $user->last_name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('user_id')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Assigned Client -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="client_id" :value="__('Client')" />
|
||||||
|
<select class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="client_id" id="client_id">
|
||||||
|
@foreach($clients as $client)
|
||||||
|
<option value="{{ $client->id }}"
|
||||||
|
@selected(old('client_id') == $client->id)>{{ $client->company_name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('client_id')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="status" :value="__('Status')" />
|
||||||
|
<select class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="status" id="status">
|
||||||
|
@foreach(\App\Enums\ProjectStatus::cases() as $status)
|
||||||
|
<option value="{{ $status->value }}" @selected(old('status') == $status->value)>{{ $status->value }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('status')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<x-primary-button class="mt-4">
|
||||||
|
{{ __('Save') }}
|
||||||
|
</x-primary-button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-app-layout>
|
||||||
82
resources/views/projects/edit.blade.php
Normal file
82
resources/views/projects/edit.blade.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||||
|
{{ __('Edit Project') }}
|
||||||
|
</h2>
|
||||||
|
</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-sm sm:rounded-lg">
|
||||||
|
<div class="overflow-hidden overflow-x-auto p-6 bg-white border-b border-gray-200">
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('projects.update', $project) }}">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<div>
|
||||||
|
<x-input-label for="title" :value="__('Title')" />
|
||||||
|
<x-text-input id="title" class="block mt-1 w-full" type="text" name="title" :value="old('title', $project->title)" required />
|
||||||
|
<x-input-error :messages="$errors->get('title')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="description" :value="__('Description')" />
|
||||||
|
<textarea id="description" class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="description" required>{{ old('description', $project->description) }}</textarea>
|
||||||
|
<x-input-error :messages="$errors->get('description')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Deadline At -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="deadline_at" :value="__('Deadline')" />
|
||||||
|
<x-text-input id="deadline_at" class="block mt-1 w-full" type="date" name="deadline_at" min="{{ today()->format('Y-m-d') }}" :value="old('deadline_at', $project->deadline_at)" required />
|
||||||
|
<x-input-error :messages="$errors->get('deadline_at')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Assigned User -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="user_id" :value="__('Assigned user')" />
|
||||||
|
<select class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="user_id" id="user_id">
|
||||||
|
@foreach($users as $user)
|
||||||
|
<option value="{{ $user->id }}"
|
||||||
|
@selected(old('user_id', $project->user_id) == $user->id)>{{ $user->first_name . ' ' . $user->last_name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('user_id')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Assigned Client -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="client_id" :value="__('Client')" />
|
||||||
|
<select class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="client_id" id="client_id">
|
||||||
|
@foreach($clients as $client)
|
||||||
|
<option value="{{ $client->id }}"
|
||||||
|
@selected(old('client_id', $project->client_id) == $client->id)>{{ $client->company_name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('client_id')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="mt-4">
|
||||||
|
<x-input-label for="status" :value="__('Status')" />
|
||||||
|
<select class="block mt-1 w-full border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm" name="status" id="status">
|
||||||
|
@foreach(\App\Enums\ProjectStatus::cases() as $status)
|
||||||
|
<option value="{{ $status->value }}" @selected(old('status', $project->status->value) == $status->value)>{{ $status->value }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<x-input-error :messages="$errors->get('status')" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<x-primary-button class="mt-4">
|
||||||
|
{{ __('Save') }}
|
||||||
|
</x-primary-button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-app-layout>
|
||||||
79
resources/views/projects/index.blade.php
Normal file
79
resources/views/projects/index.blade.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||||
|
{{ __('Projects') }}
|
||||||
|
</h2>
|
||||||
|
</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-sm sm:rounded-lg">
|
||||||
|
<div class="p-6 text-gray-900">
|
||||||
|
<a href="{{ route('projects.create') }}" class="underline">Add new project</a>
|
||||||
|
|
||||||
|
<table class="min-w-full divide-y divide-gray-200 border mt-4">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Title</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Assigned To</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Client</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Deadline</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Status</span>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200 divide-solid">
|
||||||
|
@foreach($projects as $project)
|
||||||
|
<tr class="bg-white">
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $project->title }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $project->user->first_name }} {{ $project->user->last_name }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $project->client->company_name }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $project->deadline_at }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
{{ $project->status }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||||
|
<a href="{{ route('projects.edit', $project) }}" class="underline">Edit</a>
|
||||||
|
|
|
||||||
|
<form action="{{ route('projects.destroy', $project) }}"
|
||||||
|
method="POST"
|
||||||
|
onsubmit="return confirm('Are you sure?');"
|
||||||
|
class="inline-block">
|
||||||
|
@method('DELETE')
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="text-red-500 underline">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
{{ $projects->links() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-app-layout>
|
||||||
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Controllers\ClientController;
|
||||||
use App\Http\Controllers\ProfileController;
|
use App\Http\Controllers\ProfileController;
|
||||||
|
use App\Http\Controllers\ProjectController;
|
||||||
use App\Http\Controllers\UserController;
|
use App\Http\Controllers\UserController;
|
||||||
use App\RoleEnum;
|
use App\RoleEnum;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
@ -16,6 +18,8 @@
|
|||||||
Route::middleware('auth')->group(function () {
|
Route::middleware('auth')->group(function () {
|
||||||
Route::resource('users', UserController::class)
|
Route::resource('users', UserController::class)
|
||||||
->middleware(['role:' . RoleEnum::ADMIN->value]);
|
->middleware(['role:' . RoleEnum::ADMIN->value]);
|
||||||
|
Route::resource('clients', ClientController::class);
|
||||||
|
Route::resource('projects', ProjectController::class);
|
||||||
|
|
||||||
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
|
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
|
||||||
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
|
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user