diff --git a/app/Filament/Resources/CareerResource.php b/app/Filament/Resources/CareerResource.php new file mode 100644 index 0000000..cee0268 --- /dev/null +++ b/app/Filament/Resources/CareerResource.php @@ -0,0 +1,115 @@ +schema([ + TextInput::make('title') + ->required() + ->maxLength(255), + + TextInput::make('location') + ->required() + ->maxLength(255), + + Textarea::make('title_description') + ->label('Description (show on modal)') + ->required() + ->maxLength(65535) + ->columnSpan('full'), + + TextInput::make('salary_per_month') + ->required() + ->numeric() + ->label('Salary per month') + ->maxLength(255), + Repeater::make('bullets') + ->schema([ + TextInput::make('bullet') + ->required() + ->maxLength(255), + ]) + ->minItems(1) + ->defaultItems(1) + ->columnSpan('full'), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('title') + ->searchable(), + Tables\Columns\TextColumn::make('title_description') + ->searchable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('salary_per_month') + ->searchable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('location') + ->searchable(), + Tables\Columns\TextColumn::make('salary') + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + RelationManagers\ApplicationsRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListCareers::route('/'), + 'create' => Pages\CreateCareer::route('/create'), + 'edit' => Pages\EditCareer::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/CareerResource/Pages/CreateCareer.php b/app/Filament/Resources/CareerResource/Pages/CreateCareer.php new file mode 100644 index 0000000..1cac65b --- /dev/null +++ b/app/Filament/Resources/CareerResource/Pages/CreateCareer.php @@ -0,0 +1,12 @@ +schema([ + Forms\Components\TextInput::make('name') + ->required() + ->maxLength(255), + Forms\Components\DatePicker::make('birthdate') + ->required(), + Forms\Components\FileUpload::make('resume_file') + ->required() + ->acceptedFileTypes(['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']) + ->disk('public') // or your preferred disk + ->directory('resumes'), + Forms\Components\TextInput::make('email') + ->email() + ->required() + ->maxLength(255), + Forms\Components\TextInput::make('phone_number') + ->required() + ->maxLength(20), + Forms\Components\Textarea::make('cover_letter') + ->maxLength(65535) + ->nullable() + ->columnSpan('full'), + ]); + } + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('name') + ->columns([ + Tables\Columns\TextColumn::make('name') + ->searchable() + ->sortable(), + Tables\Columns\TextColumn::make('email') + ->searchable() + ->sortable(), + Tables\Columns\TextColumn::make('phone_number') + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + // + ]) + ->headerActions([ + Tables\Actions\CreateAction::make(), + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } +} diff --git a/app/Http/Controllers/ApplicationController.php b/app/Http/Controllers/ApplicationController.php new file mode 100644 index 0000000..cbe4bff --- /dev/null +++ b/app/Http/Controllers/ApplicationController.php @@ -0,0 +1,36 @@ +validate([ + 'career_id' => 'required|exists:careers,id', + 'name' => 'required|string|max:255', + 'birthdate' => 'required|date', + 'resume_file' => 'required|file|mimes:pdf,doc,docx|max:2048', + 'email' => 'required|email|max:255', + 'phone_number' => 'required|string|max:20', + 'cover_letter' => 'nullable|string', + ]); + + $resumePath = $request->file('resume_file')->store('resumes'); + + Application::create([ + 'career_id' => $validatedData['career_id'], + 'name' => $validatedData['name'], + 'birthdate' => $validatedData['birthdate'], + 'resume_file' => $resumePath, + 'email' => $validatedData['email'], + 'phone_number' => $validatedData['phone_number'], + 'cover_letter' => $validatedData['cover_letter'] ?? null, + ]); + + return back()->with('success', 'Your application has been submitted successfully!'); + } +} diff --git a/app/Http/Controllers/CareersPageController.php b/app/Http/Controllers/CareersPageController.php index 59aeb15..d88e832 100644 --- a/app/Http/Controllers/CareersPageController.php +++ b/app/Http/Controllers/CareersPageController.php @@ -9,12 +9,9 @@ class CareersPageController extends Controller { public function index() { - return view('web.pages.careers.index'); - } + $careers = Career::query()->get(); - public function store(Request $request) - { - dd($request->all()); + return view('web.pages.careers.index', compact('careers')); } public function show(Career $career) diff --git a/app/Models/Application.php b/app/Models/Application.php new file mode 100644 index 0000000..f1f05bf --- /dev/null +++ b/app/Models/Application.php @@ -0,0 +1,25 @@ +belongsTo(Career::class); + } +} diff --git a/app/Models/Career.php b/app/Models/Career.php index aea9db4..9b031f0 100644 --- a/app/Models/Career.php +++ b/app/Models/Career.php @@ -3,13 +3,25 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; +use App\Models\Application; class Career extends Model { protected $fillable = [ 'title', - 'description', + 'title_description', + 'salary_per_month', + 'bullets', 'location', - 'salary', ]; + + protected $casts = [ + 'bullets' => 'array', + ]; + + public function applications(): HasMany + { + return $this->hasMany(Application::class); + } } diff --git a/composer.json b/composer.json index 0b2bf93..711181e 100644 --- a/composer.json +++ b/composer.json @@ -55,6 +55,10 @@ "@php artisan migrate --graceful --ansi" ], "dev": [ + "Composer\\Config::disableProcessTimeout", + "npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite" + ], + "network": [ "Composer\\Config::disableProcessTimeout", "npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve --host=0.0.0.0\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite" ], diff --git a/database/migrations/2025_07_28_122336_create_careers_table.php b/database/migrations/2025_07_28_122336_create_careers_table.php index 9479d3a..b4fe74b 100644 --- a/database/migrations/2025_07_28_122336_create_careers_table.php +++ b/database/migrations/2025_07_28_122336_create_careers_table.php @@ -14,9 +14,10 @@ return new class extends Migration Schema::create('careers', function (Blueprint $table) { $table->id(); $table->string('title'); - $table->text('description'); + $table->text('title_description')->nullable(); + $table->string('salary_per_month')->nullable(); + $table->json('bullets')->nullable(); $table->string('location'); - $table->string('salary')->nullable(); $table->timestamps(); }); } diff --git a/database/migrations/2025_07_28_215911_create_applications_table.php b/database/migrations/2025_07_28_215911_create_applications_table.php new file mode 100644 index 0000000..2aba910 --- /dev/null +++ b/database/migrations/2025_07_28_215911_create_applications_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('career_id')->constrained()->onDelete('cascade'); + $table->string('name'); + $table->date('birthdate'); + $table->string('resume_file'); + $table->string('email'); + $table->string('phone_number'); + $table->text('cover_letter')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('applications'); + } +}; diff --git a/public/web/assets/css/style.css b/public/web/assets/css/style.css index 7833456..2046da9 100644 --- a/public/web/assets/css/style.css +++ b/public/web/assets/css/style.css @@ -5538,7 +5538,7 @@ p { } .price__area-item.active .price__area-item-price h3, .price__area-item.active .price__area-item-price h2 { - color: var(--color-1); + color: var(--text-white); } .price__area-item.active .price__area-item-list { border-color: #DDB348; diff --git a/resources/views/web/pages/careers/index.blade.php b/resources/views/web/pages/careers/index.blade.php index e69de29..6aca735 100644 --- a/resources/views/web/pages/careers/index.blade.php +++ b/resources/views/web/pages/careers/index.blade.php @@ -0,0 +1,170 @@ +@extends('web.layouts.app') + +@push('header-css') + +@endpush + +@section('content') + + + + +
+
+
+
+ @forelse ($careers as $career) +
+
+ {{ $career->title }} +

{{ $career->location }}

+

{{ $career->salary_per_month }}/Per monthly

+
+
+
    + @foreach($career->bullets as $bullet) +
  • {{ $bullet['bullet'] ?? '' }}
  • + @endforeach +
+
+
+ +
+
+ @empty + No careers found... + @endforelse +
+
+
+
+ + + + + +@endsection + +@push('footer-js') + +@endpush \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 7faff48..237de93 100644 --- a/routes/web.php +++ b/routes/web.php @@ -10,6 +10,7 @@ use App\Http\Controllers\NewsPageController; use App\Http\Controllers\OurSolutionPageController; use App\Http\Controllers\StoryPageController; use App\Http\Controllers\Web\SuccessPageController; +use App\Http\Controllers\ApplicationController; use Illuminate\Support\Facades\Route; // Homepage... @@ -33,8 +34,8 @@ Route::get('success-stories/{success:slug}', [SuccessPageController::class, 'sho // Careers... Route::get('careers', [CareersPageController::class, 'index'])->name('career.index'); -Route::get('careers/{career:slug}', [CareersPageController::class, 'show'])->name('career.show'); Route::post('careers', [CareersPageController::class, 'store'])->name('career.store'); +Route::post('applications', [ApplicationController::class, 'store'])->name('applications.store'); // Internships... Route::get('internships', [InternshipsPageController::class, 'index'])->name('internship.index');