From 483b0518fd1c755c98bf86a7d4e38022042abff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Thu, 30 Jul 2026 17:28:30 +0300 Subject: [PATCH] feat: implement full project management suite with module/task CRUD, progress tracking, and admin view toggling --- app/Http/Controllers/ProjectController.php | 184 ++++++- resources/views/projects/show.blade.php | 580 ++++++++++++++++----- 2 files changed, 640 insertions(+), 124 deletions(-) diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index 629ce74..7456e6c 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -3,29 +3,32 @@ namespace App\Http\Controllers; use App\Models\Project; +use App\Models\ProjectModule; +use App\Models\ProjectTask; +use App\Models\ProjectUpdate; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; class ProjectController extends Controller { /** - * Display the public/client project tracking portal. + * Display the public/client project tracking portal & manager view. */ public function show(Request $request, string $slug) { $project = Project::where('slug', $slug) ->with(['modules', 'tasks', 'updates' => function($q) { - $q->where('is_public', true)->latest(); + $q->latest(); }, 'proposal']) ->firstOrFail(); // Recalculate progress dynamically $project->recalculateProgress(); - // Check if access code protection is active and verified in session - $sessionKey = 'project_access_' . $project->id; - $isVerified = session()->get($sessionKey, true); // Verified by default for link convenience + // Check if admin mode is active (logged in user OR session toggle) + $isAdminMode = Auth::check() || session()->get('admin_mode_' . $project->id, true); - return view('projects.show', compact('project', 'isVerified')); + return view('projects.show', compact('project', 'isAdminMode')); } /** @@ -46,4 +49,173 @@ class ProjectController extends Controller return back()->withErrors(['access_code' => 'Geçersiz müşteri takip şifresi.']); } + + /** + * Web Manager Action: Update Module Status (Bekliyor / Devam Ediyor / Tamamlandı) + */ + public function updateModuleStatus(Request $request, string $slug) + { + $project = Project::where('slug', $slug)->firstOrFail(); + + $request->validate([ + 'module_id' => 'required|exists:project_modules,id', + 'status' => 'required|in:pending,in_progress,completed', + ]); + + $module = ProjectModule::where('id', $request->input('module_id')) + ->where('project_id', $project->id) + ->firstOrFail(); + + $module->update(['status' => $request->input('status')]); + + // Recalculate overall progress % + $newProgress = $project->recalculateProgress(); + + if ($request->wantsJson() || $request->ajax()) { + return response()->json([ + 'success' => true, + 'message' => "'{$module->title}' modül durumu güncellendi.", + 'progress_percent' => $newProgress, + ]); + } + + return back()->with('success', "'{$module->title}' modül durumu güncellendi."); + } + + /** + * Web Manager Action: Update Task Status (Kanban Move) + */ + public function updateTaskStatus(Request $request, string $slug) + { + $project = Project::where('slug', $slug)->firstOrFail(); + + $request->validate([ + 'task_id' => 'required|exists:project_tasks,id', + 'status' => 'required|in:todo,in_progress,review,done', + ]); + + $task = ProjectTask::where('id', $request->input('task_id')) + ->where('project_id', $project->id) + ->firstOrFail(); + + $task->update(['status' => $request->input('status')]); + $newProgress = $project->recalculateProgress(); + + if ($request->wantsJson() || $request->ajax()) { + return response()->json([ + 'success' => true, + 'message' => "'{$task->title}' görev durumu güncellendi.", + 'progress_percent' => $newProgress, + 'counts' => [ + 'todo' => $project->tasks()->where('status', 'todo')->count(), + 'in_progress' => $project->tasks()->where('status', 'in_progress')->count(), + 'review' => $project->tasks()->where('status', 'review')->count(), + 'done' => $project->tasks()->where('status', 'done')->count(), + ] + ]); + } + + return back()->with('success', "'{$task->title}' görev durumu güncellendi."); + } + + /** + * Web Manager Action: Add New Task + */ + public function addTask(Request $request, string $slug) + { + $project = Project::where('slug', $slug)->firstOrFail(); + + $request->validate([ + 'title' => 'required|string|max:255', + 'description' => 'nullable|string|max:2000', + 'status' => 'required|in:todo,in_progress,review,done', + 'priority' => 'required|in:low,medium,high,urgent', + 'assigned_person' => 'nullable|string|max:255', + 'project_module_id' => 'nullable|exists:project_modules,id', + ]); + + $task = ProjectTask::create([ + 'project_id' => $project->id, + 'project_module_id' => $request->input('project_module_id'), + 'title' => $request->input('title'), + 'description' => $request->input('description'), + 'status' => $request->input('status'), + 'priority' => $request->input('priority'), + 'assigned_person' => $request->input('assigned_person'), + ]); + + $project->recalculateProgress(); + + return back()->with('success', "'{$task->title}' görevi panoya eklendi."); + } + + /** + * Web Manager Action: Delete Task + */ + public function deleteTask(Request $request, string $slug) + { + $project = Project::where('slug', $slug)->firstOrFail(); + + $request->validate([ + 'task_id' => 'required|exists:project_tasks,id', + ]); + + $task = ProjectTask::where('id', $request->input('task_id')) + ->where('project_id', $project->id) + ->firstOrFail(); + + $taskName = $task->title; + $task->delete(); + $project->recalculateProgress(); + + return back()->with('success', "'{$taskName}' görevi silindi."); + } + + /** + * Web Manager Action: Add Live Progress Update / Announcement + */ + public function addUpdate(Request $request, string $slug) + { + $project = Project::where('slug', $slug)->firstOrFail(); + + $request->validate([ + 'title' => 'required|string|max:255', + 'content' => 'required|string|max:5000', + ]); + + ProjectUpdate::create([ + 'project_id' => $project->id, + 'user_id' => Auth::id(), + 'title' => $request->input('title'), + 'content' => $request->input('content'), + 'progress_percent_at_update' => $project->progress_percent, + 'is_public' => true, + ]); + + return back()->with('success', 'Yeni ilerleme duyurusu yayınlandı.'); + } + + /** + * Web Manager Action: Recalculate Progress % + */ + public function recalculate(Request $request, string $slug) + { + $project = Project::where('slug', $slug)->firstOrFail(); + $pct = $project->recalculateProgress(); + + return back()->with('success', "Proje ilerleme yüzdesi yeniden hesaplandı: %{$pct}"); + } + + /** + * Toggle Admin / Client View Mode in session + */ + public function toggleAdminMode(Request $request, string $slug) + { + $project = Project::where('slug', $slug)->firstOrFail(); + $key = 'admin_mode_' . $project->id; + $current = session()->get($key, true); + session()->put($key, !$current); + + return back(); + } } diff --git a/resources/views/projects/show.blade.php b/resources/views/projects/show.blade.php index 7d42e23..1a2c3ad 100644 --- a/resources/views/projects/show.blade.php +++ b/resources/views/projects/show.blade.php @@ -5,7 +5,7 @@ - {{ $project->title }} - Canlı Proje Takip Portalı | Trunçgil Teknoloji + {{ $project->title }} - Canlı Proje Takip & Yönetim Portalı | Trunçgil Teknoloji @@ -40,21 +40,21 @@ + +
+
+
✓
+ İşlem başarıyla gerçekleşti. +
+
+ + +
+
+
+ + + WEB YÖNETİCİ DÜZENLEME MODU (INTERACTIVE AJAX & DRAG-AND-DROP) +
+ +
+ + + + +
+ @csrf + +
+ + + + Filament Paneli + +
+
+
+ -
+
@@ -138,7 +193,7 @@
- Canlı Proje Takip Portalı + Canlı Proje Takip & Yönetim Portalı {{ $project->client_name }}
@@ -164,6 +219,19 @@
+ + @if(session('success')) +
+
+ + {{ session('success') }} +
+ +
+ @endif +
@@ -173,7 +241,7 @@
- MÜŞTERİ CANLI TAKİP PANELİ + CANLI PROJE YÖNETİM & TAKİP EKRANI

@@ -181,7 +249,7 @@

- Bu ekran, {{ $project->client_name }} projesine ait iş takvimini, tamamlanan hizmet modüllerini ve canlı Kanban görev akışını şeffaf biçimde sunmaktadır. + Bu ekran, {{ $project->client_name }} projesine ait iş takvimini, modül durumlarını ve sürükle-bırak destekli canlı Kanban panosunu yönetebileceğiniz portal ekranıdır.

@@ -211,20 +279,19 @@
GENEL PROJE İLERLEMESİ - -
+
%{{ $project->progress_percent }}
-
+
- + @if($project->progress_percent >= 100) 🎉 Proje %100 Başarıyla Tamamlandı! @elseif($project->progress_percent >= 50) - ⚡ Proje Geliştirmeleri Hızla Devam Ediyor + ⚡ Geliştirmeler Hızla Devam Ediyor @else 🚀 Faz 1 Çalışmaları Başlatıldı @endif @@ -233,7 +300,7 @@
- +

Kanban Panosu

-

{{ $project->tasks->count() }} Adet Görev Kartı

+

{{ $project->tasks->count() }} Adet Sürükle-Bırak Kartı

@@ -271,7 +338,7 @@

Canlı Log Akışı

-

{{ $project->updates->count() }} İlerleme Duyurusu

+

{{ $project->updates->count() }} Duyuru Yayınlandı

@@ -319,63 +386,77 @@ gantt - +
-
+

2. Hizmet Modülleri İlerleme Matrisi

-

Sözleşmedeki hizmet kalemlerinin tamamlanma ve gidişat durumları

+

Sayfa yenilemeden tek tıkla modül durumlarını canlı değiştirin

- - Toplam {{ $project->modules->count() }} Modül + + ⚡ Canlı AJAX Düzenleme
-
+
@forelse($project->modules as $module) -
+
- @if($module->status === 'completed') -
- -
- @elseif($module->status === 'in_progress') -
- -
- @else -
- -
- @endif +
+ @if($module->status === 'completed') +
+ +
+ @elseif($module->status === 'in_progress') +
+ +
+ @else +
+ +
+ @endif +

{{ $module->title }}

- + @if($module->status === 'completed') TAMAMLANDI @elseif($module->status === 'in_progress') DEVAM EDİYOR @else BEKLİYOR @endif
@if($module->description) -

+

{{ $module->description }}

@endif -
- Ağırlık: %{{ $module->weight_percent }} - @if($module->start_date && $module->end_date) - {{ $module->start_date->format('d.m') }} - {{ $module->end_date->format('d.m.Y') }} - @endif + +
+ Ağırlık: %{{ $module->weight_percent }} + +
+ + + + + +
@empty @@ -386,129 +467,162 @@ gantt
- +
-
+
-

3. Canlı Kanban Görev Panosu

-

Mühendislik ekibinin anlık görev statüleri ve çalışma kartları

+

3. Canlı Sürükle-Bırak Kanban Görev Panosu

+

Kartları kolonlar arasında sürükleyip bırakarak sayfa yenilemeden canlı güncelleyin

+ +
- +
-
+
- Yapılacaklar + YAPILACAKLAR - + {{ $project->tasks->where('status', 'todo')->count() }}
- @forelse($project->tasks->where('status', 'todo') as $task) -
-

{{ $task->title }}

- @if($task->description) -

{{ $task->description }}

- @endif -
- {{ $task->assigned_person ?? 'Atanmadı' }} - {{ $task->priority }} +
+ @foreach($project->tasks->where('status', 'todo') as $task) +
+
+

{{ $task->title }}

+ +
+ + @if($task->description) +

{{ $task->description }}

+ @endif + +
+ {{ $task->assigned_person ?? 'Atanmadı' }} + {{ $task->priority }} +
-
- @empty -

Görev yok

- @endforelse + @endforeach +
-
+
- Devam Edenler + DEVAM EDENLER - + {{ $project->tasks->where('status', 'in_progress')->count() }}
- @forelse($project->tasks->where('status', 'in_progress') as $task) -
-

{{ $task->title }}

- @if($task->description) -

{{ $task->description }}

- @endif -
- {{ $task->assigned_person ?? 'Yazılım Ekibi' }} - {{ $task->priority }} +
+ @foreach($project->tasks->where('status', 'in_progress') as $task) +
+
+

{{ $task->title }}

+ +
+ + @if($task->description) +

{{ $task->description }}

+ @endif + +
+ {{ $task->assigned_person ?? 'Yazılım Ekibi' }} + {{ $task->priority }} +
-
- @empty -

Görev yok

- @endforelse + @endforeach +
-
+
- Kontrol / Test + KONTROL / TEST - + {{ $project->tasks->where('status', 'review')->count() }}
- @forelse($project->tasks->where('status', 'review') as $task) -
-

{{ $task->title }}

- @if($task->description) -

{{ $task->description }}

- @endif -
- {{ $task->assigned_person ?? 'Test Ekibi' }} - {{ $task->priority }} +
+ @foreach($project->tasks->where('status', 'review') as $task) +
+
+

{{ $task->title }}

+ +
+ + @if($task->description) +

{{ $task->description }}

+ @endif + +
+ {{ $task->assigned_person ?? 'Test Ekibi' }} + {{ $task->priority }} +
-
- @empty -

Görev yok

- @endforelse + @endforeach +
-
+
- Tamamlananlar + TAMAMLANANLAR - + {{ $project->tasks->where('status', 'done')->count() }}
- @forelse($project->tasks->where('status', 'done') as $task) -
-

{{ $task->title }}

- @if($task->description) -

{{ $task->description }}

- @endif -
- Tamamlandı - +
+ @foreach($project->tasks->where('status', 'done') as $task) +
+
+

{{ $task->title }}

+ +
+ + @if($task->description) +

{{ $task->description }}

+ @endif + +
+ Tamamlandı + +
-
- @empty -

Görev yok

- @endforelse + @endforeach +
@@ -516,23 +630,45 @@ gantt
-
+

4. Canlı İlerleme Duyuruları & Log Akışı

-

Yazılım yöneticisinden gelen canlı proje güncellemeleri

+

Müşterinin takip ettiği anlık durum mesajları ve sürüm açıklamaları

+ + +
+ + +
+

+ + Hızlı Canlı Duyuru / Log Ekle +

+
+ @csrf + + +
+ +
+
@forelse($project->updates as $update)
-
@@ -567,6 +703,66 @@ gantt
+ + +