feat: Add Vacancy management functionality with controller, model, migration, and form
This commit is contained in:
147
Modules/CCMS/app/Http/Controllers/VacancyController.php
Normal file
147
Modules/CCMS/app/Http/Controllers/VacancyController.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\CCMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Modules\CCMS\Models\Vacancy;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
class VacancyController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
|
||||
public function index()
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
$model = Vacancy::query()->latest();
|
||||
return DataTables::eloquent($model)
|
||||
->addIndexColumn()
|
||||
// ->setRowClass(function (Vacancy $vacancy) {
|
||||
// return $vacancy->is_read ? 'text-muted' : 'text-dark';
|
||||
// })
|
||||
// ->editColumn('class', function (Vacancy $vacancy) {
|
||||
// return $vacancy->class ?? '-';
|
||||
// })
|
||||
// ->editColumn('subject', function (Vacancy $vacancy) {
|
||||
// return $vacancy->subject ?? '-';
|
||||
// })
|
||||
// ->editColumn('message', function (Vacancy $vacancy) {
|
||||
// return $vacancy->message ?? '-';
|
||||
// })
|
||||
->addColumn('action', 'ccms::vacancy.datatable.action')
|
||||
->rawColumns(['action'])
|
||||
->toJson();
|
||||
}
|
||||
return view('ccms::vacancy.index', [
|
||||
'title' => 'Vacancy List',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
// $rules = [
|
||||
|
||||
|
||||
// ];
|
||||
|
||||
// if (setting('enable_reCaptcha') == 1) {
|
||||
// $rules['g-recaptcha-response'] = ['required', new Recaptcha];
|
||||
// }
|
||||
|
||||
// $messages = [
|
||||
// 'email.email' => 'Must be a valid email address.',
|
||||
// 'g-recaptcha-response.required' => 'Please complete reCAPTCHA validation.',
|
||||
// 'g-recaptcha-response' => 'Invalid reCAPTCHA.',
|
||||
// ];
|
||||
|
||||
// $validator = Validator::make($request->all());
|
||||
// if ($validator->fails()) {
|
||||
// return response()->json(['errors' => $validator->errors()], 422);
|
||||
// }
|
||||
|
||||
$modelClass = "Modules\\CCMS\\Models\\Career";
|
||||
|
||||
$model = $modelClass::findOrFail($request->career_id);
|
||||
foreach ($request->document as $file) {
|
||||
$model->addToDocumentCollection(collectionName: 'uploads/document', file: $file, documentName: $request->first_name, referenceDocumentId: null);
|
||||
}
|
||||
|
||||
Vacancy::create($request->all());
|
||||
|
||||
return response()->json(['status' => 200, 'message' => "Thank you for reaching out! Your message has been received and we'll get back to you shortly."], 200);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['status' => 500, 'message' => 'Internal server error', 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
$vacancy = Vacancy::whereId($id)->first();
|
||||
if ($vacancy) {
|
||||
$vacancy->delete();
|
||||
}
|
||||
return response()->json(['status' => 200, 'message' => 'Vacancy has been deleted!'], 200);
|
||||
} catch (\Throwable $th) {
|
||||
return redirect()->back()->with('error', $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function markAsRead($id)
|
||||
{
|
||||
try {
|
||||
$vacancy = Vacancy::whereId($id)->first();
|
||||
if ($vacancy) {
|
||||
$vacancy->update(['is_read' => 1]);
|
||||
}
|
||||
return response()->json(['status' => 200, 'message' => 'Vacancy has been marked as read!'], 200);
|
||||
} catch (\Throwable $th) {
|
||||
return redirect()->back()->with('error', $th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
21
Modules/CCMS/app/Models/Vacancy.php
Normal file
21
Modules/CCMS/app/Models/Vacancy.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\CCMS\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// use Modules\CCMS\Database\Factories\VacancyFactory;
|
||||
|
||||
class vacancy extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'phone',
|
||||
'qualification',
|
||||
'description',
|
||||
];
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
<?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::create('vacancies', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('first_name')->nullable();
|
||||
$table->string('last_name')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('phone')->nullable();
|
||||
$table->string('qualification')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('vacancies');
|
||||
}
|
||||
};
|
@@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Route;
|
||||
use Modules\CCMS\Http\Controllers\EnquiryController;
|
||||
use Modules\CCMS\Http\Controllers\FranchiseController;
|
||||
use Modules\CCMS\Http\Controllers\NewsletterController;
|
||||
use Modules\CCMS\Http\Controllers\VacancyController;
|
||||
use Modules\CCMS\Models\Franchise;
|
||||
use Modules\CourseFinder\Http\Controllers\CoopController;
|
||||
use Modules\CourseFinder\Http\Controllers\ProgramController;
|
||||
@@ -24,6 +25,7 @@ Route::get('getCoursesList', [ProgramController::class, 'getCoursesList'])->name
|
||||
Route::post('enquiry', [EnquiryController::class, 'store'])->name('enquiry.store');
|
||||
Route::post('franchise', [FranchiseController::class, 'store'])->name('franchise.store');
|
||||
Route::post('newsletter', [NewsletterController::class, 'store'])->name('newsletter.store');
|
||||
Route::post('vacancy', [VacancyController::class, 'store'])->name('vacancy.store');
|
||||
|
||||
Route::get('career/{id}', [WebsiteController::class, 'careerSingle'])->name('career.single');
|
||||
|
||||
|
@@ -11,6 +11,7 @@ trait AddToDocumentCollection
|
||||
{
|
||||
public function addToDocumentCollection(string $collectionName = 'uploads', string $file, ?string $documentName = null, ?int $referenceDocumentId = null)
|
||||
{
|
||||
dd($documentName);
|
||||
if (!Storage::disk('public')->exists($collectionName)) {
|
||||
Storage::disk('public')->makeDirectory($collectionName);
|
||||
}
|
||||
|
@@ -339,6 +339,46 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const form = document.getElementById('vacancy-form');
|
||||
const submitBtn = document.getElementById('vacancy-submit-btn');
|
||||
const url = form.action;
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Submitting…';
|
||||
const formData = new FormData(form);
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')
|
||||
.content
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
form.reset();
|
||||
window.location.href =
|
||||
"{{ route('thankyou') }}"; // ✅ redirect instead of toastr
|
||||
} else if (data.errors && data.errors.email) {
|
||||
data.errors.email.forEach(msg => toastr.error(msg));
|
||||
} else {
|
||||
toastr.error('Submission failed. Please try again.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toastr.error('Something went wrong. Please try again.');
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Submit';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var weekdays = [
|
||||
|
@@ -89,35 +89,37 @@
|
||||
<div class="col col-12 col-md-5">
|
||||
<div class=" form ">
|
||||
<h2 class="text-26 mb-30 text-brand text-center">Quick Apply</h2>
|
||||
<form action="">
|
||||
<form action="{{ route('vacancy.store') }}" method="post" id="vacancy-form">
|
||||
@csrf
|
||||
<input type="hidden" name="career_id" value="{{ $career->id }}">
|
||||
<div class="flex gap-20">
|
||||
<input class="w-full mb-30 rounded-6 py-15 text-14 px-10" type="text"
|
||||
name="" id="" placeholder="First Name">
|
||||
name="first_name" id="" placeholder="First Name">
|
||||
<input class="w-full mb-30 rounded-6 py-15 text-14 px-10" type="text"
|
||||
name="" id="" placeholder="Last Name">
|
||||
name="last_name" id="" placeholder="Last Name">
|
||||
</div>
|
||||
|
||||
<div class="flex gap-20">
|
||||
<input class="w-full mb-30 rounded-6 py-15 text-14 px-10" type="email"
|
||||
name="" id="" placeholder="Email">
|
||||
name="email" id="" placeholder="Email">
|
||||
|
||||
<input class="w-full mb-30 rounded-6 py-15 text-14 px-10" type="tel"
|
||||
name="" id="" placeholder="Phone Number">
|
||||
name="phone" id="" placeholder="Phone Number">
|
||||
</div>
|
||||
|
||||
|
||||
<input class="w-full mb-30 rounded-6 py-15 text-14 px-10" type="text" name=""
|
||||
id="" placeholder="Your Qualification">
|
||||
<input class="w-full mb-30 rounded-6 py-15 text-14 px-10" type="text"
|
||||
name="qualification" id="" placeholder="Your Qualification">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<textarea class="w-full mb-10 rounded-6 py-15 text-14 px-10" name="" id=""
|
||||
<textarea class="w-full mb-10 rounded-6 py-15 text-14 px-10" name="description" id=""
|
||||
placeholder="Short description about you"></textarea>
|
||||
<label class="text-16" for="">Please Upload Your CV</label>
|
||||
<input class="mb-20" type="file" name="" id="">
|
||||
<button
|
||||
<input class="mb-20" type="file" name="document" id="">
|
||||
<button type="submit" id="vacancy-submit-btn"
|
||||
class="button-hover px-30 py-10 bg-sec text-white rounded-30 text-14 border-0 mt-20 ">Submit</button>
|
||||
</form>
|
||||
|
||||
|
Reference in New Issue
Block a user