refactor: migrate career applications to separate job and intern Filament resources
This commit is contained in:
@@ -1,55 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Admin\Resources\CareerApplications;
|
|
||||||
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\Pages\CreateCareerApplication;
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\Pages\EditCareerApplication;
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\Pages\ListCareerApplications;
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\Schemas\CareerApplicationForm;
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\Tables\CareerApplicationsTable;
|
|
||||||
use App\Models\CareerApplication;
|
|
||||||
use BackedEnum;
|
|
||||||
use Filament\Resources\Resource;
|
|
||||||
use Filament\Schemas\Schema;
|
|
||||||
use Filament\Tables\Table;
|
|
||||||
|
|
||||||
class CareerApplicationResource extends Resource
|
|
||||||
{
|
|
||||||
protected static ?string $model = CareerApplication::class;
|
|
||||||
|
|
||||||
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-user-group';
|
|
||||||
|
|
||||||
public static function getNavigationLabel(): string
|
|
||||||
{
|
|
||||||
return __('career.navigation_label');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getModelLabel(): string
|
|
||||||
{
|
|
||||||
return __('career.model_label');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getPluralModelLabel(): string
|
|
||||||
{
|
|
||||||
return __('career.plural_model_label');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function form(Schema $schema): Schema
|
|
||||||
{
|
|
||||||
return CareerApplicationForm::configure($schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function table(Table $table): Table
|
|
||||||
{
|
|
||||||
return CareerApplicationsTable::configure($table);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getPages(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'index' => ListCareerApplications::route('/'),
|
|
||||||
'create' => CreateCareerApplication::route('/create'),
|
|
||||||
'edit' => EditCareerApplication::route('/{record}/edit'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Admin\Resources\CareerApplications\Pages;
|
|
||||||
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\CareerApplicationResource;
|
|
||||||
use Filament\Resources\Pages\CreateRecord;
|
|
||||||
|
|
||||||
class CreateCareerApplication extends CreateRecord
|
|
||||||
{
|
|
||||||
protected static string $resource = CareerApplicationResource::class;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Admin\Resources\CareerApplications\Pages;
|
|
||||||
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\CareerApplicationResource;
|
|
||||||
use Filament\Actions\CreateAction;
|
|
||||||
use Filament\Resources\Pages\ListRecords;
|
|
||||||
|
|
||||||
class ListCareerApplications extends ListRecords
|
|
||||||
{
|
|
||||||
protected static string $resource = CareerApplicationResource::class;
|
|
||||||
|
|
||||||
protected function getHeaderActions(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
CreateAction::make(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Admin\Resources\CareerApplications\Tables;
|
|
||||||
|
|
||||||
use Filament\Actions\Action;
|
|
||||||
use Filament\Actions\DeleteAction;
|
|
||||||
use Filament\Actions\BulkActionGroup;
|
|
||||||
use Filament\Actions\DeleteBulkAction;
|
|
||||||
use Filament\Tables\Columns\TextColumn;
|
|
||||||
use Filament\Tables\Filters\SelectFilter;
|
|
||||||
use Filament\Tables\Table;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class CareerApplicationsTable
|
|
||||||
{
|
|
||||||
public static function configure(Table $table): Table
|
|
||||||
{
|
|
||||||
return $table
|
|
||||||
->columns([
|
|
||||||
TextColumn::make('name')
|
|
||||||
->label(__('career.name'))
|
|
||||||
->searchable()
|
|
||||||
->sortable(),
|
|
||||||
|
|
||||||
TextColumn::make('email')
|
|
||||||
->label(__('career.email'))
|
|
||||||
->searchable()
|
|
||||||
->sortable(),
|
|
||||||
|
|
||||||
TextColumn::make('phone')
|
|
||||||
->label(__('career.phone'))
|
|
||||||
->searchable(),
|
|
||||||
|
|
||||||
TextColumn::make('type')
|
|
||||||
->label(__('career.type'))
|
|
||||||
->badge()
|
|
||||||
->color(fn (string $state): string => match ($state) {
|
|
||||||
'job' => 'success',
|
|
||||||
'internship' => 'warning',
|
|
||||||
default => 'gray',
|
|
||||||
})
|
|
||||||
->formatStateUsing(fn (string $state): string => __("career.{$state}")),
|
|
||||||
|
|
||||||
TextColumn::make('status')
|
|
||||||
->label(__('career.status'))
|
|
||||||
->badge()
|
|
||||||
->color(fn (string $state): string => match ($state) {
|
|
||||||
'pending' => 'gray',
|
|
||||||
'reviewed' => 'info',
|
|
||||||
'rejected' => 'danger',
|
|
||||||
'accepted' => 'success',
|
|
||||||
'waiting_document' => 'warning',
|
|
||||||
default => 'gray',
|
|
||||||
})
|
|
||||||
->formatStateUsing(fn (string $state): string => __("career.{$state}")),
|
|
||||||
|
|
||||||
TextColumn::make('git_knowledge')
|
|
||||||
->label(__('career.git_knowledge'))
|
|
||||||
->badge()
|
|
||||||
->color(fn ($state) => $state ? 'success' : 'danger')
|
|
||||||
->formatStateUsing(fn ($state) => $state ? 'Evet' : 'Hayır'),
|
|
||||||
|
|
||||||
TextColumn::make('ai_usage')
|
|
||||||
->label(__('career.ai_usage'))
|
|
||||||
->badge()
|
|
||||||
->color(fn ($state) => $state ? 'success' : 'danger')
|
|
||||||
->formatStateUsing(fn ($state) => $state ? 'Evet' : 'Hayır'),
|
|
||||||
|
|
||||||
TextColumn::make('created_at')
|
|
||||||
->label(__('career.created_at'))
|
|
||||||
->dateTime('d.m.Y H:i')
|
|
||||||
->sortable(),
|
|
||||||
])
|
|
||||||
->filters([
|
|
||||||
SelectFilter::make('status')
|
|
||||||
->label(__('career.status'))
|
|
||||||
->options([
|
|
||||||
'pending' => __('career.pending'),
|
|
||||||
'reviewed' => __('career.reviewed'),
|
|
||||||
'rejected' => __('career.rejected'),
|
|
||||||
'accepted' => __('career.accepted'),
|
|
||||||
'waiting_document' => __('career.waiting_document'),
|
|
||||||
]),
|
|
||||||
SelectFilter::make('type')
|
|
||||||
->label(__('career.type'))
|
|
||||||
->options([
|
|
||||||
'job' => __('career.job'),
|
|
||||||
'internship' => __('career.internship'),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
->actions([
|
|
||||||
Action::make('download_cv')
|
|
||||||
->label(__('career.download_cv'))
|
|
||||||
->icon('heroicon-o-arrow-down-tray')
|
|
||||||
->url(fn ($record) => Storage::disk('public')->url($record->cv_path))
|
|
||||||
->openUrlInNewTab(),
|
|
||||||
Action::make('download_signed_form')
|
|
||||||
->label('İmzalı Form İndir')
|
|
||||||
->icon('heroicon-o-document-check')
|
|
||||||
->url(fn ($record) => $record->signed_internship_form_path ? Storage::disk('public')->url($record->signed_internship_form_path) : null)
|
|
||||||
->visible(fn ($record) => !empty($record->signed_internship_form_path))
|
|
||||||
->openUrlInNewTab(),
|
|
||||||
Action::make('download_nda')
|
|
||||||
->label(__('career.nda'))
|
|
||||||
->icon('heroicon-o-shield-check')
|
|
||||||
->url(fn ($record) => $record->nda_path ? Storage::disk('public')->url($record->nda_path) : null)
|
|
||||||
->visible(fn ($record) => $record->nda_path !== null)
|
|
||||||
->openUrlInNewTab(),
|
|
||||||
Action::make('download_contract')
|
|
||||||
->label(__('career.contract'))
|
|
||||||
->icon('heroicon-o-document-text')
|
|
||||||
->url(fn ($record) => $record->contract_path ? Storage::disk('public')->url($record->contract_path) : null)
|
|
||||||
->visible(fn ($record) => $record->contract_path !== null)
|
|
||||||
->openUrlInNewTab(),
|
|
||||||
DeleteAction::make(),
|
|
||||||
])
|
|
||||||
->bulkActions([
|
|
||||||
BulkActionGroup::make([
|
|
||||||
DeleteBulkAction::make(),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
->defaultSort('created_at', 'desc');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+169
-11
@@ -1,25 +1,59 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Filament\Admin\Resources\CareerApplications\Schemas;
|
namespace App\Filament\Admin\Resources\InternApplications;
|
||||||
|
|
||||||
|
use App\Models\CareerApplication;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Tables\Table;
|
||||||
use Filament\Forms\Components\FileUpload;
|
use Filament\Forms\Components\FileUpload;
|
||||||
use Filament\Forms\Components\Select;
|
use Filament\Forms\Components\Select;
|
||||||
use Filament\Forms\Components\Textarea;
|
use Filament\Forms\Components\Textarea;
|
||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Forms\Components\DatePicker;
|
use Filament\Forms\Components\DatePicker;
|
||||||
use Filament\Schemas\Components\Section;
|
use Filament\Forms\Components\MarkdownEditor;
|
||||||
use Filament\Schemas\Schema;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Filament\Actions\Action;
|
|
||||||
use Filament\Schemas\Components\Utilities\Set;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Filament\Schemas\Components\Tabs;
|
use Filament\Schemas\Components\Tabs;
|
||||||
use Filament\Schemas\Components\Tabs\Tab;
|
use Filament\Schemas\Components\Tabs\Tab;
|
||||||
use Filament\Schemas\Components\Livewire;
|
use Filament\Schemas\Components\Livewire;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Filters\SelectFilter;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Actions\BulkActionGroup;
|
||||||
|
use Filament\Actions\DeleteBulkAction;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Filament\Schemas\Components\Utilities\Set;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
class CareerApplicationForm
|
class InternApplicationResource extends Resource
|
||||||
{
|
{
|
||||||
public static function configure(Schema $schema): Schema
|
protected static ?string $model = CareerApplication::class;
|
||||||
|
|
||||||
|
protected static \BackedEnum|string|null $navigationIcon = 'heroicon-o-academic-cap';
|
||||||
|
|
||||||
|
public static function getNavigationLabel(): string
|
||||||
|
{
|
||||||
|
return __('career.internship_title', ['default' => 'Staj Başvuruları']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getModelLabel(): string
|
||||||
|
{
|
||||||
|
return __('career.internship', ['default' => 'Staj Başvurusu']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPluralModelLabel(): string
|
||||||
|
{
|
||||||
|
return __('career.internship_title', ['default' => 'Staj Başvuruları']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getEloquentQuery(): Builder
|
||||||
|
{
|
||||||
|
return parent::getEloquentQuery()->where('type', 'internship');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function form(Schema $schema): Schema
|
||||||
{
|
{
|
||||||
return $schema
|
return $schema
|
||||||
->components([
|
->components([
|
||||||
@@ -85,7 +119,7 @@ class CareerApplicationForm
|
|||||||
->placeholder('Şifreyi değiştirmek istemiyorsanız boş bırakın')
|
->placeholder('Şifreyi değiştirmek istemiyorsanız boş bırakın')
|
||||||
->nullable()
|
->nullable()
|
||||||
->suffixAction(
|
->suffixAction(
|
||||||
Action::make('generatePassword')
|
\Filament\Actions\Action::make('generatePassword')
|
||||||
->icon('heroicon-m-arrow-path')
|
->icon('heroicon-m-arrow-path')
|
||||||
->action(fn (Set $set) => $set('password', Str::random(12)))
|
->action(fn (Set $set) => $set('password', Str::random(12)))
|
||||||
),
|
),
|
||||||
@@ -141,11 +175,126 @@ class CareerApplicationForm
|
|||||||
|
|
||||||
Livewire::make(\App\Livewire\InternJournalTimeline::class)
|
Livewire::make(\App\Livewire\InternJournalTimeline::class)
|
||||||
->columnSpanFull()
|
->columnSpanFull()
|
||||||
])
|
]),
|
||||||
|
|
||||||
|
Tab::make('Sertifika & Transkript')
|
||||||
|
->icon('heroicon-o-academic-cap')
|
||||||
|
->schema([
|
||||||
|
TextInput::make('certificate_code')
|
||||||
|
->label('Doğrulama Kodu')
|
||||||
|
->helperText('Belge kaydedildiğinde benzersiz doğrulama kodu otomatik olarak üretilir.')
|
||||||
|
->readonly()
|
||||||
|
->nullable(),
|
||||||
|
|
||||||
|
MarkdownEditor::make('transcript_markdown')
|
||||||
|
->label('Akademik Transkript (Markdown)')
|
||||||
|
->columnSpanFull()
|
||||||
|
->default(function () {
|
||||||
|
return "### STAJ AKADEMİK TRANSKRİPTİ VE PERFORMANS RAPORU\n\n" .
|
||||||
|
"#### 🛠️ Deneyimlenen Teknolojiler ve Kazanımlar\n" .
|
||||||
|
"| Modül / Çalışma Alanı | Kullanılan Teknolojiler / Araçlar | Değerlendirme |\n" .
|
||||||
|
"| --- | --- | --- |\n" .
|
||||||
|
"| Backend Mimari & API | Laravel framework, RESTful API, MySQL | Başarılı |\n" .
|
||||||
|
"| Arayüz & UI/UX Uygulamaları | Flutter, CSS, Glassmorphic Tasarım Prensipleri | Üstün Başarı |\n" .
|
||||||
|
"| Masaüstü & Sistem Entegrasyonu | Electron.js, Git / GitHub | Başarılı |\n" .
|
||||||
|
"| Takım Çalışması & Proje Yönetimi | Agile / Scrum, Slack, JIRA | Başarılı |\n\n" .
|
||||||
|
"#### 📊 Performans Değerlendirme Kriterleri\n" .
|
||||||
|
"| Değerlendirme Kriteri | Puan (100 Üzerinden) | Harf Notu |\n" .
|
||||||
|
"| --- | --- | --- |\n" .
|
||||||
|
"| Teknik Sorumluluk ve Görev Bilinci | 95 | AA |\n" .
|
||||||
|
"| Problem Çözme ve Analitik Düşünme | 90 | BA |\n" .
|
||||||
|
"| Ekip Çalışması ve İletişim Uyum | 95 | AA |\n" .
|
||||||
|
"| Öğrenme Hızı ve Adaptasyon | 100 | AA |\n" .
|
||||||
|
"| **GENEL BAŞARI ORTALAMASI** | **95.00** | **AA (Mükemmel)** |\n\n" .
|
||||||
|
"#### 📝 Danışman Görüşü ve Değerlendirme Notu\n" .
|
||||||
|
"\"Stajyerimiz, staj süresi boyunca kendisine verilen görevleri büyük bir titizlikle yerine getirmiştir. Özellikle karşılaştığı teknik problemlere getirdiği pratik çözümler ve yeni teknolojileri öğrenme isteği takdir edilmeye değerdir. Kurumumuz bünyesinde yürüttüğümüz projelere sağladığı katkılardan ötürü teşekkür eder, profesyonel kariyerinde başarılar dileriz.\"";
|
||||||
|
}),
|
||||||
|
])->columns(1)
|
||||||
])->columnSpanFull()
|
])->columnSpanFull()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('name')
|
||||||
|
->label(__('career.name'))
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('email')
|
||||||
|
->label(__('career.email'))
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('phone')
|
||||||
|
->label(__('career.phone'))
|
||||||
|
->searchable(),
|
||||||
|
|
||||||
|
TextColumn::make('status')
|
||||||
|
->label(__('career.status'))
|
||||||
|
->badge()
|
||||||
|
->color(fn (string $state): string => match ($state) {
|
||||||
|
'pending' => 'gray',
|
||||||
|
'reviewed' => 'info',
|
||||||
|
'rejected' => 'danger',
|
||||||
|
'accepted' => 'success',
|
||||||
|
'waiting_document' => 'warning',
|
||||||
|
default => 'gray',
|
||||||
|
})
|
||||||
|
->formatStateUsing(fn (string $state): string => __("career.{$state}")),
|
||||||
|
|
||||||
|
TextColumn::make('certificate_code')
|
||||||
|
->label('Sertifika Kodu')
|
||||||
|
->searchable()
|
||||||
|
->placeholder('Yok'),
|
||||||
|
|
||||||
|
TextColumn::make('created_at')
|
||||||
|
->label(__('career.created_at'))
|
||||||
|
->dateTime('d.m.Y H:i')
|
||||||
|
->sortable(),
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
SelectFilter::make('status')
|
||||||
|
->label(__('career.status'))
|
||||||
|
->options([
|
||||||
|
'pending' => __('career.pending'),
|
||||||
|
'reviewed' => __('career.reviewed'),
|
||||||
|
'rejected' => __('career.rejected'),
|
||||||
|
'accepted' => __('career.accepted'),
|
||||||
|
'waiting_document' => __('career.waiting_document'),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->actions([
|
||||||
|
Action::make('download_cv')
|
||||||
|
->label(__('career.download_cv'))
|
||||||
|
->icon('heroicon-o-arrow-down-tray')
|
||||||
|
->url(fn ($record) => Storage::disk('public')->url($record->cv_path))
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
Action::make('download_signed_form')
|
||||||
|
->label('İmzalı Form İndir')
|
||||||
|
->icon('heroicon-o-document-check')
|
||||||
|
->url(fn ($record) => $record->signed_internship_form_path ? Storage::disk('public')->url($record->signed_internship_form_path) : null)
|
||||||
|
->visible(fn ($record) => !empty($record->signed_internship_form_path))
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
Action::make('view_certificate')
|
||||||
|
->label('Sertifika Doğrulama')
|
||||||
|
->icon('heroicon-o-academic-cap')
|
||||||
|
->color('success')
|
||||||
|
->url(fn ($record) => $record->certificate_code ? route('internship.verify', $record->certificate_code) : null)
|
||||||
|
->visible(fn ($record) => !empty($record->certificate_code))
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
DeleteAction::make(),
|
||||||
|
])
|
||||||
|
->bulkActions([
|
||||||
|
BulkActionGroup::make([
|
||||||
|
DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->defaultSort('created_at', 'desc');
|
||||||
|
}
|
||||||
|
|
||||||
public static function calculateTotalDays($start, $end, Set $set): void
|
public static function calculateTotalDays($start, $end, Set $set): void
|
||||||
{
|
{
|
||||||
if (!$start || !$end) {
|
if (!$start || !$end) {
|
||||||
@@ -197,4 +346,13 @@ class CareerApplicationForm
|
|||||||
|
|
||||||
$set('internship_end_date', $endDate->format('Y-m-d'));
|
$set('internship_end_date', $endDate->format('Y-m-d'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => Pages\ListInternApplications::route('/'),
|
||||||
|
'create' => Pages\CreateInternApplication::route('/create'),
|
||||||
|
'edit' => Pages\EditInternApplication::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\InternApplications\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\InternApplications\InternApplicationResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreateInternApplication extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = InternApplicationResource::class;
|
||||||
|
}
|
||||||
+4
-4
@@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Filament\Admin\Resources\CareerApplications\Pages;
|
namespace App\Filament\Admin\Resources\InternApplications\Pages;
|
||||||
|
|
||||||
use App\Filament\Admin\Resources\CareerApplications\CareerApplicationResource;
|
use App\Filament\Admin\Resources\InternApplications\InternApplicationResource;
|
||||||
use Filament\Actions\DeleteAction;
|
use Filament\Actions\DeleteAction;
|
||||||
use Filament\Resources\Pages\EditRecord;
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
class EditCareerApplication extends EditRecord
|
class EditInternApplication extends EditRecord
|
||||||
{
|
{
|
||||||
protected static string $resource = CareerApplicationResource::class;
|
protected static string $resource = InternApplicationResource::class;
|
||||||
|
|
||||||
protected function getHeaderActions(): array
|
protected function getHeaderActions(): array
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\InternApplications\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\InternApplications\InternApplicationResource;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListInternApplications extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = InternApplicationResource::class;
|
||||||
|
}
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\JobApplications;
|
||||||
|
|
||||||
|
use App\Models\CareerApplication;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
use Filament\Forms\Components\FileUpload;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Forms\Components\Textarea;
|
||||||
|
use Filament\Forms\Components\TextInput;
|
||||||
|
use Filament\Forms\Components\Toggle;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Filters\SelectFilter;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Actions\BulkActionGroup;
|
||||||
|
use Filament\Actions\DeleteBulkAction;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
|
class JobApplicationResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = CareerApplication::class;
|
||||||
|
|
||||||
|
protected static \BackedEnum|string|null $navigationIcon = 'heroicon-o-briefcase';
|
||||||
|
|
||||||
|
public static function getNavigationLabel(): string
|
||||||
|
{
|
||||||
|
return __('career.job_application_title', ['default' => 'İş Başvuruları']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getModelLabel(): string
|
||||||
|
{
|
||||||
|
return __('career.job', ['default' => 'İş Başvurusu']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPluralModelLabel(): string
|
||||||
|
{
|
||||||
|
return __('career.job_application_title', ['default' => 'İş Başvuruları']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getEloquentQuery(): Builder
|
||||||
|
{
|
||||||
|
return parent::getEloquentQuery()->where('type', 'job');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function form(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return $schema
|
||||||
|
->components([
|
||||||
|
TextInput::make('name')
|
||||||
|
->label(__('career.name'))
|
||||||
|
->required()
|
||||||
|
->disabled(),
|
||||||
|
|
||||||
|
TextInput::make('email')
|
||||||
|
->label(__('career.email'))
|
||||||
|
->email()
|
||||||
|
->required()
|
||||||
|
->disabled(),
|
||||||
|
|
||||||
|
TextInput::make('phone')
|
||||||
|
->label(__('career.phone'))
|
||||||
|
->disabled(),
|
||||||
|
|
||||||
|
Select::make('status')
|
||||||
|
->label(__('career.status'))
|
||||||
|
->options([
|
||||||
|
'pending' => __('career.pending'),
|
||||||
|
'reviewed' => __('career.reviewed'),
|
||||||
|
'rejected' => __('career.rejected'),
|
||||||
|
'accepted' => __('career.accepted'),
|
||||||
|
'waiting_document' => __('career.waiting_document'),
|
||||||
|
])
|
||||||
|
->required(),
|
||||||
|
|
||||||
|
FileUpload::make('cv_path')
|
||||||
|
->label(__('career.cv'))
|
||||||
|
->disk('public')
|
||||||
|
->directory('cvs')
|
||||||
|
->required()
|
||||||
|
->disabled()
|
||||||
|
->downloadable(),
|
||||||
|
|
||||||
|
FileUpload::make('nda_path')
|
||||||
|
->label(__('career.nda'))
|
||||||
|
->disk('public')
|
||||||
|
->directory('ndas')
|
||||||
|
->disabled()
|
||||||
|
->downloadable(),
|
||||||
|
|
||||||
|
FileUpload::make('contract_path')
|
||||||
|
->label(__('career.contract'))
|
||||||
|
->disk('public')
|
||||||
|
->directory('contracts')
|
||||||
|
->disabled()
|
||||||
|
->downloadable(),
|
||||||
|
|
||||||
|
FileUpload::make('id_photocopy_path')
|
||||||
|
->label(__('career.id_photocopy', ['default' => 'Kimlik Fotokopisi']))
|
||||||
|
->disk('public')
|
||||||
|
->directory('id_photocopies')
|
||||||
|
->disabled()
|
||||||
|
->downloadable(),
|
||||||
|
|
||||||
|
Toggle::make('git_knowledge')
|
||||||
|
->label(__('career.git_knowledge'))
|
||||||
|
->disabled(),
|
||||||
|
|
||||||
|
Toggle::make('ai_usage')
|
||||||
|
->label(__('career.ai_usage'))
|
||||||
|
->disabled(),
|
||||||
|
|
||||||
|
Textarea::make('message')
|
||||||
|
->label(__('career.message'))
|
||||||
|
->disabled()
|
||||||
|
->columnSpanFull(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('name')
|
||||||
|
->label(__('career.name'))
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('email')
|
||||||
|
->label(__('career.email'))
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('phone')
|
||||||
|
->label(__('career.phone'))
|
||||||
|
->searchable(),
|
||||||
|
|
||||||
|
TextColumn::make('status')
|
||||||
|
->label(__('career.status'))
|
||||||
|
->badge()
|
||||||
|
->color(fn (string $state): string => match ($state) {
|
||||||
|
'pending' => 'gray',
|
||||||
|
'reviewed' => 'info',
|
||||||
|
'rejected' => 'danger',
|
||||||
|
'accepted' => 'success',
|
||||||
|
'waiting_document' => 'warning',
|
||||||
|
default => 'gray',
|
||||||
|
})
|
||||||
|
->formatStateUsing(fn (string $state): string => __("career.{$state}")),
|
||||||
|
|
||||||
|
TextColumn::make('git_knowledge')
|
||||||
|
->label(__('career.git_knowledge'))
|
||||||
|
->badge()
|
||||||
|
->color(fn ($state) => $state ? 'success' : 'danger')
|
||||||
|
->formatStateUsing(fn ($state) => $state ? 'Evet' : 'Hayır'),
|
||||||
|
|
||||||
|
TextColumn::make('ai_usage')
|
||||||
|
->label(__('career.ai_usage'))
|
||||||
|
->badge()
|
||||||
|
->color(fn ($state) => $state ? 'success' : 'danger')
|
||||||
|
->formatStateUsing(fn ($state) => $state ? 'Evet' : 'Hayır'),
|
||||||
|
|
||||||
|
TextColumn::make('created_at')
|
||||||
|
->label(__('career.created_at'))
|
||||||
|
->dateTime('d.m.Y H:i')
|
||||||
|
->sortable(),
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
SelectFilter::make('status')
|
||||||
|
->label(__('career.status'))
|
||||||
|
->options([
|
||||||
|
'pending' => __('career.pending'),
|
||||||
|
'reviewed' => __('career.reviewed'),
|
||||||
|
'rejected' => __('career.rejected'),
|
||||||
|
'accepted' => __('career.accepted'),
|
||||||
|
'waiting_document' => __('career.waiting_document'),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->actions([
|
||||||
|
Action::make('download_cv')
|
||||||
|
->label(__('career.download_cv'))
|
||||||
|
->icon('heroicon-o-arrow-down-tray')
|
||||||
|
->url(fn ($record) => Storage::disk('public')->url($record->cv_path))
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
Action::make('download_nda')
|
||||||
|
->label(__('career.nda'))
|
||||||
|
->icon('heroicon-o-shield-check')
|
||||||
|
->url(fn ($record) => $record->nda_path ? Storage::disk('public')->url($record->nda_path) : null)
|
||||||
|
->visible(fn ($record) => $record->nda_path !== null)
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
Action::make('download_contract')
|
||||||
|
->label(__('career.contract'))
|
||||||
|
->icon('heroicon-o-document-text')
|
||||||
|
->url(fn ($record) => $record->contract_path ? Storage::disk('public')->url($record->contract_path) : null)
|
||||||
|
->visible(fn ($record) => $record->contract_path !== null)
|
||||||
|
->openUrlInNewTab(),
|
||||||
|
DeleteAction::make(),
|
||||||
|
])
|
||||||
|
->bulkActions([
|
||||||
|
BulkActionGroup::make([
|
||||||
|
DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->defaultSort('created_at', 'desc');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => Pages\ListJobApplications::route('/'),
|
||||||
|
'create' => Pages\CreateJobApplication::route('/create'),
|
||||||
|
'edit' => Pages\EditJobApplication::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\JobApplications\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\JobApplications\JobApplicationResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreateJobApplication extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = JobApplicationResource::class;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\JobApplications\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\JobApplications\JobApplicationResource;
|
||||||
|
use Filament\Actions\DeleteAction;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditJobApplication extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = JobApplicationResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
DeleteAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Admin\Resources\JobApplications\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Admin\Resources\JobApplications\JobApplicationResource;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListJobApplications extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = JobApplicationResource::class;
|
||||||
|
}
|
||||||
@@ -312,4 +312,19 @@ class CareerController extends Controller
|
|||||||
session()->forget('intern_id');
|
session()->forget('intern_id');
|
||||||
return redirect()->route('intern.login')->with('success', 'Başarıyla çıkış yapıldı.');
|
return redirect()->route('intern.login')->with('success', 'Başarıyla çıkış yapıldı.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function verifyCertificate($code)
|
||||||
|
{
|
||||||
|
$application = CareerApplication::where('certificate_code', $code)
|
||||||
|
->where('type', 'internship')
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
return view('front.career.verify', [
|
||||||
|
'application' => $application,
|
||||||
|
'meta' => [
|
||||||
|
'title' => 'Staj Bitirme Sertifikası Doğrulama - ' . $application->name,
|
||||||
|
'description' => $application->name . ' isimli stajyerimizin staj bitirme sertifikası ve performans raporu doğrulama sayfası.',
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,22 @@ class CareerApplication extends Model
|
|||||||
'internship_end_date',
|
'internship_end_date',
|
||||||
'internship_total_days',
|
'internship_total_days',
|
||||||
'github_repo',
|
'github_repo',
|
||||||
|
'certificate_code',
|
||||||
|
'transcript_markdown',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
static::saving(function ($model) {
|
||||||
|
if ($model->type === 'internship' && !$model->certificate_code) {
|
||||||
|
do {
|
||||||
|
$code = 'TRN-' . date('Y') . '-' . strtoupper(\Illuminate\Support\Str::random(4)) . '-' . strtoupper(\Illuminate\Support\Str::random(4));
|
||||||
|
} while (static::where('certificate_code', $code)->exists());
|
||||||
|
$model->certificate_code = $code;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the attributes that should be cast.
|
* Get the attributes that should be cast.
|
||||||
*
|
*
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
<?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::table('career_applications', function (Blueprint $table) {
|
||||||
|
$table->string('certificate_code')->nullable()->unique();
|
||||||
|
$table->text('transcript_markdown')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('career_applications', function (Blueprint $table) {
|
||||||
|
$table->dropColumn(['certificate_code', 'transcript_markdown']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
@extends('layouts.site')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@500;700;800&family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,500;0,700;1,400&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<div class="bg-slate-50 py-12 no-print">
|
||||||
|
<div class="container max-w-4xl mx-auto px-4">
|
||||||
|
<!-- Verification Banner (e-Devlet Style) -->
|
||||||
|
<div class="bg-emerald-50 border-l-4 border-emerald-500 p-6 rounded-2xl shadow-sm mb-8 flex flex-col md:flex-row items-center justify-between gap-6">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-emerald-500 text-white flex items-center justify-center flex-shrink-0 shadow-lg shadow-emerald-500/20">
|
||||||
|
<i class="uil uil-shield-check text-2xl"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold text-slate-800">Güvenli Belge Doğrulama</h3>
|
||||||
|
<p class="text-sm text-slate-500 mt-1">Bu belge, Trunçgil Teknoloji Belge Doğrulama Sistemi ile doğrulanmıştır.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button onclick="window.print()" class="px-6 py-3 bg-slate-900 hover:bg-slate-800 text-white font-bold rounded-xl transition-all shadow-md flex items-center gap-2">
|
||||||
|
<i class="uil uil-print text-lg"></i>
|
||||||
|
<span>Yazdır / PDF Kaydet</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Printable Area -->
|
||||||
|
<div class="print-container">
|
||||||
|
<div class="container max-w-4xl mx-auto px-4 pb-20">
|
||||||
|
<!-- Page 1: Internship Certificate (Staj Bitirme Sertifikası) -->
|
||||||
|
<div class="certificate-page bg-white rounded-3xl shadow-2xl border-8 border-slate-100 p-8 md:p-16 relative overflow-hidden mb-12 page-break">
|
||||||
|
<!-- Decorative Corners -->
|
||||||
|
<div class="absolute top-0 left-0 w-32 h-32 border-t-4 border-l-4 border-red-500/20 rounded-tl-3xl"></div>
|
||||||
|
<div class="absolute top-0 right-0 w-32 h-32 border-t-4 border-r-4 border-red-500/20 rounded-tr-3xl"></div>
|
||||||
|
<div class="absolute bottom-0 left-0 w-32 h-32 border-b-4 border-l-4 border-red-500/20 rounded-bl-3xl"></div>
|
||||||
|
<div class="absolute bottom-0 right-0 w-32 h-32 border-b-4 border-r-4 border-red-500/20 rounded-br-3xl"></div>
|
||||||
|
|
||||||
|
<div class="relative z-10 flex flex-col items-center justify-between h-full min-h-[700px] text-center">
|
||||||
|
<!-- Logo -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<img src="https://truncgil.com.tr/assets/img/logo.png" alt="Trunçgil Teknoloji" class="h-16 object-contain" onerror="this.src='/assets/img/logo.png'">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Certificate Title -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1 class="font-serif text-3xl md:text-5xl font-extrabold tracking-widest text-slate-900 uppercase">Staj Bitirme Sertifikası</h1>
|
||||||
|
<div class="w-32 h-1 bg-red-600 rounded-full mx-auto mt-4"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recipient Info -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<span class="text-sm font-medium text-slate-500 uppercase tracking-widest block mb-2">Sayın</span>
|
||||||
|
<h2 class="font-serif text-2xl md:text-4xl font-bold text-slate-900 tracking-wide">{{ $application->name }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Body Text -->
|
||||||
|
<div class="max-w-2xl mx-auto mb-10 leading-relaxed text-slate-700 text-sm md:text-lg">
|
||||||
|
<p>
|
||||||
|
<strong>{{ \Carbon\Carbon::parse($application->internship_start_date)->format('d.m.Y') }}</strong> -
|
||||||
|
<strong>{{ \Carbon\Carbon::parse($application->internship_end_date)->format('d.m.Y') }}</strong> tarihleri arasında,
|
||||||
|
<strong>Trunçgil Teknoloji</strong> bünyesinde gerçekleştirdiği staj programını başarıyla tamamlamıştır.
|
||||||
|
</p>
|
||||||
|
<p class="mt-4">
|
||||||
|
Staj süresi boyunca gösterdiği üstün gayret, sorumluluk bilinci, teknik beceriler ve ekip çalışmasına sağladığı değerli katkılardan dolayı bu belgeyi almaya hak kazanmıştır.
|
||||||
|
</p>
|
||||||
|
<p class="mt-4 text-sm md:text-base italic font-serif">
|
||||||
|
Kendisine gelecekteki eğitim ve profesyonel kariyer hayatında başarılar dileriz.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer Section (Signatures & Verification Code) -->
|
||||||
|
<div class="w-full grid grid-cols-1 md:grid-cols-3 items-end gap-8 pt-8 border-t border-slate-100">
|
||||||
|
<!-- Left: Verification Details & QR Code -->
|
||||||
|
<div class="flex flex-col items-center md:items-start text-center md:text-start">
|
||||||
|
<div class="mb-3">
|
||||||
|
<img src="https://api.qrserver.com/v1/create-qr-code/?size=100x100&data={{ urlencode(route('internship.verify', $application->certificate_code)) }}" alt="QR Code" class="w-24 h-24 border border-slate-200 p-1 rounded-lg">
|
||||||
|
</div>
|
||||||
|
<span class="text-[10px] font-bold text-slate-400 uppercase tracking-wider block">Belge Doğrulama Kodu</span>
|
||||||
|
<span class="text-xs font-mono font-bold text-slate-800">{{ $application->certificate_code }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Middle: Date -->
|
||||||
|
<div class="text-center pb-4">
|
||||||
|
<span class="text-xs text-slate-500 block uppercase tracking-wider">Düzenlenme Tarihi</span>
|
||||||
|
<span class="text-sm font-semibold text-slate-800">{{ \Carbon\Carbon::parse($application->internship_end_date)->format('d.m.Y') }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right: Authorizing Signature -->
|
||||||
|
<div class="text-center md:text-end">
|
||||||
|
<div class="inline-block pb-4 text-center">
|
||||||
|
<!-- Placeholder signature or company stamp stamp -->
|
||||||
|
<div class="h-12 flex items-center justify-center mb-1">
|
||||||
|
<span class="font-serif italic text-red-700 font-bold">Trunçgil Teknoloji</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-bold text-slate-800 block text-sm">Onaylayan</span>
|
||||||
|
<span class="text-xs text-slate-500 block">Staj Koordinatörü & Kurucu</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Page 2: Internship Academic Transcript (Staj Akademik Transkripti) -->
|
||||||
|
<div class="transcript-page bg-white rounded-3xl shadow-2xl border-8 border-slate-100 p-8 md:p-16 relative overflow-hidden">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="flex flex-col md:flex-row justify-between items-center pb-8 border-b-2 border-slate-100 mb-8 gap-4">
|
||||||
|
<div class="text-center md:text-left">
|
||||||
|
<h2 class="font-serif text-2xl font-bold text-slate-900 uppercase">Staj Akademik Transkripti</h2>
|
||||||
|
<p class="text-xs text-slate-500 tracking-wider uppercase mt-1">Ve Performans Raporu</p>
|
||||||
|
</div>
|
||||||
|
<img src="https://truncgil.com.tr/assets/img/logo.png" alt="Trunçgil Logo" class="h-10 object-contain" onerror="this.src='/assets/img/logo.png'">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Student Info Metadata Block -->
|
||||||
|
<div class="bg-slate-50 rounded-2xl p-6 border border-slate-100 mb-8">
|
||||||
|
<h3 class="text-xs font-bold text-slate-400 uppercase tracking-widest mb-4">Öğrenci / Stajyer Bilgileri</h3>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-y-4 gap-x-8 text-sm">
|
||||||
|
<div class="flex justify-between border-b border-slate-200/50 pb-2">
|
||||||
|
<span class="text-slate-500">Adı Soyadı:</span>
|
||||||
|
<strong class="text-slate-800">{{ $application->name }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between border-b border-slate-200/50 pb-2">
|
||||||
|
<span class="text-slate-500">E-Posta:</span>
|
||||||
|
<strong class="text-slate-800">{{ $application->email }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between border-b border-slate-200/50 pb-2">
|
||||||
|
<span class="text-slate-500">Staj Dönemi:</span>
|
||||||
|
<strong class="text-slate-800">{{ \Carbon\Carbon::parse($application->internship_start_date)->format('d.m.Y') }} - {{ \Carbon\Carbon::parse($application->internship_end_date)->format('d.m.Y') }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between border-b border-slate-200/50 pb-2">
|
||||||
|
<span class="text-slate-500">Toplam Süre:</span>
|
||||||
|
<strong class="text-slate-800">{{ $application->internship_total_days }} İş Günü</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dynamic Markdown Content -->
|
||||||
|
<div class="prose max-w-none text-slate-700 text-sm leading-relaxed mb-10">
|
||||||
|
{!! new \Illuminate\Support\HtmlString(\Illuminate\Support\Str::markdown($application->transcript_markdown ?? '')) !!}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Validation Info and QR Code at the bottom of Page 2 -->
|
||||||
|
<div class="w-full flex flex-col md:flex-row justify-between items-center pt-8 border-t border-slate-100 gap-6">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<img src="https://api.qrserver.com/v1/create-qr-code/?size=100x100&data={{ urlencode(route('internship.verify', $application->certificate_code)) }}" alt="QR Code" class="w-16 h-16 border border-slate-200 p-1 rounded-lg">
|
||||||
|
<div>
|
||||||
|
<span class="text-[10px] font-bold text-slate-400 uppercase tracking-wider block">Güvenli Doğrulama Kodu</span>
|
||||||
|
<span class="text-sm font-mono font-bold text-slate-800 block">{{ $application->certificate_code }}</span>
|
||||||
|
<span class="text-[10px] text-slate-500 block">Bu belge e-Devlet benzeri karekod okutularak sorgulanabilir.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center md:text-right text-xs text-slate-400">
|
||||||
|
Trunçgil Teknoloji San. ve Tic. Ltd. Şti.<br>
|
||||||
|
Teknopark No: 4A Gaziantep
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@push('styles')
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
.font-serif {
|
||||||
|
font-family: 'Cinzel', 'Playfair Display', Georgia, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Elegant Markdown Table Styling inside prose */
|
||||||
|
.prose table {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
border-collapse: collapse;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.prose th {
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background-color: #f8fafc;
|
||||||
|
border-bottom: 2px solid #e2e8f0;
|
||||||
|
color: #1e293b;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
.prose td {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-bottom: 1px solid #e2e8f0;
|
||||||
|
color: #334155;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.prose tr:hover {
|
||||||
|
background-color: #f8fafc/50;
|
||||||
|
}
|
||||||
|
.prose h3 {
|
||||||
|
font-family: 'Cinzel', serif;
|
||||||
|
color: #0f172a;
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid #e2e8f0;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.prose h4 {
|
||||||
|
color: #1e293b;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.prose blockquote {
|
||||||
|
border-left: 4px solid #ef4444;
|
||||||
|
padding-left: 1rem;
|
||||||
|
font-style: italic;
|
||||||
|
color: #475569;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
header, footer, nav, .site-header, .site-footer, .no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
body, html {
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
.print-container {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.page-break {
|
||||||
|
page-break-after: always !important;
|
||||||
|
break-after: page !important;
|
||||||
|
}
|
||||||
|
.certificate-page, .transcript-page {
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 15mm !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
height: 297mm !important; /* Perfect A4 height */
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
}
|
||||||
|
.certificate-page {
|
||||||
|
border: 4px double #cbd5e1 !important; /* nice thin double border on print */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
@endsection
|
||||||
@@ -122,6 +122,7 @@ Route::get('/stajyer/panel', [\App\Http\Controllers\CareerController::class, 'in
|
|||||||
Route::post('/stajyer/form-yukle', [\App\Http\Controllers\CareerController::class, 'uploadInternshipForm'])->name('intern.upload-form');
|
Route::post('/stajyer/form-yukle', [\App\Http\Controllers\CareerController::class, 'uploadInternshipForm'])->name('intern.upload-form');
|
||||||
Route::post('/stajyer/github-kaydet', [\App\Http\Controllers\CareerController::class, 'saveGithubRepo'])->name('intern.save-github');
|
Route::post('/stajyer/github-kaydet', [\App\Http\Controllers\CareerController::class, 'saveGithubRepo'])->name('intern.save-github');
|
||||||
Route::get('/stajyer/gunluk-indir', [\App\Http\Controllers\CareerController::class, 'downloadMarkdown'])->name('intern.download-journal');
|
Route::get('/stajyer/gunluk-indir', [\App\Http\Controllers\CareerController::class, 'downloadMarkdown'])->name('intern.download-journal');
|
||||||
|
Route::get('/staj-dogrulama/{code}', [\App\Http\Controllers\CareerController::class, 'verifyCertificate'])->name('internship.verify');
|
||||||
Route::post('/stajyer/cikis', [\App\Http\Controllers\CareerController::class, 'internLogout'])->name('intern.logout');
|
Route::post('/stajyer/cikis', [\App\Http\Controllers\CareerController::class, 'internLogout'])->name('intern.logout');
|
||||||
|
|
||||||
// Payment Process
|
// Payment Process
|
||||||
|
|||||||
Reference in New Issue
Block a user