diff --git a/app/Filament/Admin/Resources/InternApplications/InternApplicationResource.php b/app/Filament/Admin/Resources/InternApplications/InternApplicationResource.php index 71abce1..53e4779 100644 --- a/app/Filament/Admin/Resources/InternApplications/InternApplicationResource.php +++ b/app/Filament/Admin/Resources/InternApplications/InternApplicationResource.php @@ -187,6 +187,66 @@ class InternApplicationResource extends Resource ->columnSpanFull() ]), + Tab::make('Staj Defteri & Onay') + ->icon('heroicon-o-book-open') + ->schema([ + \Filament\Forms\Components\Placeholder::make('notebook_view') + ->label('Doldurulan Staj Defteri') + ->content(function ($record) { + if (!$record) return 'Henüz başvuru bulunmamaktadır.'; + $days = \App\Http\Controllers\CareerController::getInternshipDates($record->internship_start_date, $record->internship_total_days); + if (empty($days)) return 'Staj başlangıç tarihi veya süresi girilmemiş.'; + + $saved = $record->journalEntries()->get()->keyBy('day_number'); + + $html = '
'; + foreach ($days as $d) { + $dayNum = $d['day_number']; + $dateF = $d['formatted_date']; + $content = isset($saved[$dayNum]) ? $saved[$dayNum]->content : ''; + + $html .= '
'; + $html .= '
'; + $html .= ' ' . $dayNum . '. Gün Raporu'; + $html .= ' ' . $dateF . ''; + $html .= '
'; + $html .= '
' . ($content ? e($content) : 'Rapor yazılmamış') . '
'; + $html .= '
'; + } + $html .= '
'; + + // Add preview buttons + $html .= '
'; + $html .= ' A4 Defteri Önizle / Yazdır'; + $html .= ' A5 Defteri Önizle / Yazdır'; + $html .= '
'; + + return new \Illuminate\Support\HtmlString($html); + }) + ->columnSpanFull(), + + \Filament\Forms\Components\Section::make('Onay ve İmza Bilgileri') + ->schema([ + \Filament\Forms\Components\Toggle::make('notebook_supervisor_signed') + ->label('Staj Sorumlusu İmzala / Onayla') + ->live(), + TextInput::make('notebook_supervisor_name') + ->label('Staj Sorumlusu Adı / Ünvanı') + ->placeholder('Örn: Alperen Trunç') + ->default('Alperen Trunç'), + \Filament\Forms\Components\Toggle::make('notebook_unit_signed') + ->label('İlgili Birim Yetkilisi İmzala / Onayla') + ->live(), + TextInput::make('notebook_unit_name') + ->label('Birim Yetkilisi Adı / Ünvanı') + ->placeholder('Örn: Yetkili Birim Amiri') + ->default('Yetkili Birim Amiri'), + \Filament\Forms\Components\Toggle::make('notebook_approved') + ->label('Staj Defterini Genel Olarak Onayla') + ->columnSpanFull(), + ])->columns(2), + ]), + Tab::make('Sertifika & Transkript') ->icon('heroicon-o-academic-cap') ->schema([ diff --git a/app/Http/Controllers/CareerController.php b/app/Http/Controllers/CareerController.php index 427e16e..91b4785 100644 --- a/app/Http/Controllers/CareerController.php +++ b/app/Http/Controllers/CareerController.php @@ -122,8 +122,13 @@ class CareerController extends Controller } $intern = CareerApplication::findOrFail(session('intern_id')); + $days = self::getInternshipDates($intern->internship_start_date, $intern->internship_total_days); + $savedEntries = $intern->journalEntries()->get()->keyBy('day_number'); + return view('front.career.intern_dashboard', [ 'intern' => $intern, + 'days' => $days, + 'savedEntries' => $savedEntries, 'meta' => [ 'title' => 'Stajyer Paneli', 'description' => 'Belgelerinizi buradan indirebilirsiniz.', @@ -327,8 +332,13 @@ class CareerController extends Controller ->where('type', 'internship') ->firstOrFail(); + $days = self::getInternshipDates($application->internship_start_date, $application->internship_total_days); + $savedEntries = $application->journalEntries()->get()->keyBy('day_number'); + return view('front.career.verify', [ 'application' => $application, + 'days' => $days, + 'savedEntries' => $savedEntries, 'meta' => [ 'title' => 'Staj Bitirme Sertifikası Doğrulama - ' . $application->name, 'description' => $application->name . ' isimli stajyerimizin staj bitirme sertifikası ve performans raporu doğrulama sayfası.', @@ -418,5 +428,95 @@ class CareerController extends Controller auth()->logout(); return redirect()->route('intern.admin.login')->with('success', 'Yönetici oturumu sonlandırıldı.'); } + + public static function getInternshipDates($startDate, $totalDays) + { + if (!$startDate || !$totalDays || $totalDays <= 0) { + return []; + } + + $dates = []; + $temp = \Carbon\Carbon::parse($startDate); + $daysToAdd = intval($totalDays); + $count = 0; + + while ($count < $daysToAdd) { + if ($temp->isWeekend()) { + $temp->addDay(); + continue; + } + $dates[] = [ + 'day_number' => $count + 1, + 'date' => $temp->format('Y-m-d'), + 'formatted_date' => $temp->format('d.m.Y'), + ]; + $temp->addDay(); + $count++; + } + + return $dates; + } + + public function saveJournalEntry(Request $request) + { + if (!session()->has('intern_id')) { + return response()->json(['success' => false, 'message' => 'Lütfen giriş yapın.'], 401); + } + + $intern = CareerApplication::findOrFail(session('intern_id')); + + $request->validate([ + 'day_number' => 'required|integer|min:1', + 'date' => 'required|date', + 'content' => 'nullable|string', + ]); + + $dateObj = \Carbon\Carbon::parse($request->date); + if ($dateObj->isWeekend()) { + return response()->json(['success' => false, 'message' => 'Hafta sonu günlerine staj günlüğü girilemez.'], 422); + } + + $entry = \App\Models\InternshipJournalEntry::updateOrCreate([ + 'career_application_id' => $intern->id, + 'day_number' => $request->day_number, + 'date' => $request->date, + ], [ + 'content' => $request->content, + ]); + + return response()->json([ + 'success' => true, + 'message' => $request->day_number . '. Gün kaydı başarıyla kaydedildi.', + 'entry' => $entry + ]); + } + + public function printJournal(Request $request) + { + if (request()->has('intern_id') && auth()->check() && auth()->user()->hasRole('super_admin')) { + $internId = request('intern_id'); + } else { + if (!session()->has('intern_id')) { + return redirect()->route('intern.login')->with('error', 'Lütfen önce giriş yapın.'); + } + $internId = session('intern_id'); + } + + $intern = CareerApplication::findOrFail($internId); + $size = $request->query('size', 'a4'); + if (!in_array($size, ['a4', 'a5'])) { + $size = 'a4'; + } + + $days = self::getInternshipDates($intern->internship_start_date, $intern->internship_total_days); + $savedEntries = $intern->journalEntries()->get()->keyBy('day_number'); + + return view('front.career.print', [ + 'intern' => $intern, + 'days' => $days, + 'savedEntries' => $savedEntries, + 'size' => $size, + ]); + } } diff --git a/app/Models/CareerApplication.php b/app/Models/CareerApplication.php index 120f58a..5444579 100644 --- a/app/Models/CareerApplication.php +++ b/app/Models/CareerApplication.php @@ -32,8 +32,21 @@ class CareerApplication extends Model 'github_repo', 'certificate_code', 'transcript_markdown', + 'notebook_supervisor_signed', + 'notebook_supervisor_name', + 'notebook_unit_signed', + 'notebook_unit_name', + 'notebook_approved', ]; + /** + * Get the journal entries for the internship application. + */ + public function journalEntries() + { + return $this->hasMany(InternshipJournalEntry::class); + } + protected static function booted() { static::saving(function ($model) { @@ -58,6 +71,9 @@ class CareerApplication extends Model { return [ 'password' => 'hashed', + 'notebook_supervisor_signed' => 'boolean', + 'notebook_unit_signed' => 'boolean', + 'notebook_approved' => 'boolean', ]; } } diff --git a/app/Models/InternshipJournalEntry.php b/app/Models/InternshipJournalEntry.php new file mode 100644 index 0000000..dbbb949 --- /dev/null +++ b/app/Models/InternshipJournalEntry.php @@ -0,0 +1,26 @@ +belongsTo(CareerApplication::class); + } +} diff --git a/database/migrations/2026_07_01_180000_create_internship_journal_entries_table.php b/database/migrations/2026_07_01_180000_create_internship_journal_entries_table.php new file mode 100644 index 0000000..3c97d02 --- /dev/null +++ b/database/migrations/2026_07_01_180000_create_internship_journal_entries_table.php @@ -0,0 +1,36 @@ +id(); + $table->foreignId('career_application_id') + ->constrained('career_applications') + ->onDelete('cascade'); + $table->integer('day_number'); + $table->date('date'); + $table->text('content')->nullable(); + $table->timestamps(); + + $table->unique(['career_application_id', 'day_number'], 'journal_app_day_unique'); + $table->unique(['career_application_id', 'date'], 'journal_app_date_unique'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('internship_journal_entries'); + } +}; diff --git a/database/migrations/2026_07_01_180001_add_notebook_approval_fields_to_career_applications.php b/database/migrations/2026_07_01_180001_add_notebook_approval_fields_to_career_applications.php new file mode 100644 index 0000000..b81c006 --- /dev/null +++ b/database/migrations/2026_07_01_180001_add_notebook_approval_fields_to_career_applications.php @@ -0,0 +1,38 @@ +boolean('notebook_supervisor_signed')->default(false); + $table->string('notebook_supervisor_name')->nullable(); + $table->boolean('notebook_unit_signed')->default(false); + $table->string('notebook_unit_name')->nullable(); + $table->boolean('notebook_approved')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('career_applications', function (Blueprint $table) { + $table->dropColumn([ + 'notebook_supervisor_signed', + 'notebook_supervisor_name', + 'notebook_unit_signed', + 'notebook_unit_name', + 'notebook_approved' + ]); + }); + } +}; diff --git a/resources/views/front/career/intern_dashboard.blade.php b/resources/views/front/career/intern_dashboard.blade.php index 80d349a..aa385cd 100644 --- a/resources/views/front/career/intern_dashboard.blade.php +++ b/resources/views/front/career/intern_dashboard.blade.php @@ -367,14 +367,14 @@ - + @@ -619,9 +619,7 @@ @if($intern->signed_internship_form_path) - - İndir - + @else - @if($intern->github_repo) - - - Günlüğü İndir (.md) - - @endif @@ -662,61 +661,82 @@ {{ $intern->github_repo ? 'Güncelle' : 'Kaydet' }} - Deponuzun public (herkese açık) olması ve en az bir commit içermesi gerekmektedir. + Deponuzun public (herkese açık) olması gerekmektedir. - -