feat: implement comprehensive project management and client tracking portal with Filament integration

This commit is contained in:
Ümit Tunç
2026-07-30 17:25:05 +03:00
parent 4576739e6e
commit 26cab615f1
16 changed files with 1558 additions and 0 deletions
@@ -0,0 +1,259 @@
<?php
namespace App\Filament\Admin\Resources\Projects\Schemas;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Schema;
use Illuminate\Support\Str;
class ProjectForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->schema([
Tabs::make('ProjectTabs')
->tabs([
Tab::make('Proje Detayları & Müşteri')
->icon('heroicon-m-briefcase')
->schema([
Section::make('Temel Proje Bilgileri')
->columns(12)
->schema([
TextInput::make('title')
->label('Proje Adı')
->required()
->maxLength(255)
->live(onBlur: true)
->afterStateUpdated(function (string $operation, $state, callable $set) {
if ($operation !== 'create') return;
$set('slug', Str::slug($state));
})
->columnSpan(6),
TextInput::make('slug')
->label('URL Slug')
->required()
->maxLength(255)
->unique(ignoreRecord: true)
->rules(['alpha_dash'])
->columnSpan(6),
TextInput::make('client_name')
->label('Müşteri Unvanı / Firma')
->required()
->maxLength(255)
->columnSpan(4),
TextInput::make('client_email')
->label('Müşteri E-Posta')
->email()
->maxLength(255)
->columnSpan(4),
TextInput::make('client_access_code')
->label('Müşteri Giriş Şifresi / PIN')
->default(fn () => strtoupper(Str::random(6)))
->helperText('Müşterinin takip ekranına giriş yapabileceği şifre')
->columnSpan(4),
Select::make('proposal_id')
->label('İlişkili Fiyat Teklifi')
->relationship('proposal', 'title')
->searchable()
->preload()
->nullable()
->live()
->afterStateUpdated(function ($state, callable $set) {
if ($state) {
$prop = \App\Models\Proposal::find($state);
if ($prop) {
$set('slug', $prop->slug);
}
}
})
->columnSpan(4),
Select::make('status')
->label('Proje Genel Durumu')
->options([
'planning' => 'Planlama Aşamasında',
'in_progress' => 'Devam Ediyor (Aktif)',
'on_hold' => 'Beklemeye Alındı',
'completed' => 'Tamamlandı',
'cancelled' => 'İptal Edildi',
])
->default('in_progress')
->required()
->columnSpan(4),
TextInput::make('progress_percent')
->label('İlerleme Yüzdesi (%)')
->numeric()
->default(0)
->suffix('%')
->columnSpan(4),
DatePicker::make('start_date')
->label('Proje Başlangıç Tarihi')
->native(false)
->displayFormat('d.m.Y')
->columnSpan(6),
DatePicker::make('target_date')
->label('Hedef Bitiş Tarihi')
->native(false)
->displayFormat('d.m.Y')
->columnSpan(6),
Textarea::make('notes')
->label('İç Notlar ve Açıklamalar')
->rows(3)
->columnSpanFull(),
]),
]),
Tab::make('Hizmet Modülleri (% İlerleme)')
->icon('heroicon-m-squares-2x2')
->schema([
Section::make('Sözleşme Kapsamındaki Modüller')
->description('Hangi modüllerin tamamlandığını işaretleyin. İlerleme yüzdesi modül ağırlıklarına göre otomatik hesaplanır.')
->schema([
Repeater::make('modules')
->relationship('modules')
->columns(12)
->orderColumn('order')
->defaultItems(0)
->schema([
TextInput::make('title')
->label('Modül Adı')
->required()
->columnSpan(4),
TextInput::make('weight_percent')
->label('Ağırlık (%)')
->numeric()
->default(10)
->suffix('%')
->columnSpan(2),
Select::make('status')
->label('Durum')
->options([
'pending' => 'Bekliyor',
'in_progress' => 'Devam Ediyor',
'completed' => 'Tamamlandı',
])
->default('pending')
->required()
->columnSpan(3),
DatePicker::make('start_date')
->label('Başlangıç')
->native(false)
->columnSpan(1.5),
DatePicker::make('end_date')
->label('Bitiş')
->native(false)
->columnSpan(1.5),
])
->columnSpanFull(),
]),
]),
Tab::make('Kanban Görev Kartları')
->icon('heroicon-m-view-columns')
->schema([
Section::make('İş Takvimi ve Görev Listesi')
->description('Sözleşmedeki taskları ve detaylı görev kartlarını burada yönetin.')
->schema([
Repeater::make('tasks')
->relationship('tasks')
->columns(12)
->orderColumn('order_index')
->defaultItems(0)
->schema([
TextInput::make('title')
->label('Görev Başlığı')
->required()
->columnSpan(4),
Select::make('status')
->label('Kanban Durumu')
->options([
'todo' => 'Yapılacak',
'in_progress' => 'Devam Ediyor',
'review' => 'Kontrol Bekliyor',
'done' => 'Tamamlandı',
])
->default('todo')
->required()
->columnSpan(3),
Select::make('priority')
->label('Öncelik')
->options([
'low' => 'Düşük',
'medium' => 'Orta',
'high' => 'Yüksek',
'urgent' => 'Acil',
])
->default('medium')
->columnSpan(2),
TextInput::make('assigned_person')
->label('Sorumlu')
->columnSpan(3),
])
->columnSpanFull(),
]),
]),
Tab::make('Gidişat Güncellemeleri Logu')
->icon('heroicon-m-chat-bubble-bottom-center-text')
->schema([
Section::make('Canlı İlerleme Duyuruları')
->description('Yazılım ekibi tarafından girilen ve müşterinin canlı izleyebildiği durum mesajları.')
->schema([
Repeater::make('updates')
->relationship('updates')
->columns(12)
->defaultItems(0)
->schema([
TextInput::make('title')
->label('Güncelleme Başlığı')
->required()
->columnSpan(6),
TextInput::make('progress_percent_at_update')
->label('O Anki Yüzde (%)')
->numeric()
->columnSpan(3),
Checkbox::make('is_public')
->label('Müşteriye Göster')
->default(true)
->columnSpan(3),
Textarea::make('content')
->label('Güncelleme Notu / Sürüm Açıklaması')
->required()
->rows(2)
->columnSpanFull(),
])
->columnSpanFull(),
]),
]),
])->columnSpanFull()
]);
}
}