Enhance internship application process: update InternshipsPageController to retrieve internships and validate application submissions, modify Internship model to include relationships, and implement dynamic application modals in views for internships and careers. Update Livewire configuration for improved file upload handling.
This commit is contained in:
@@ -47,7 +47,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="price__area-item-btn">
|
||||
<button type="button" class="build_button apply-now-button" data-bs-toggle="modal" data-bs-target="#applicationModal" data-career-title="{{ $career->title }}" data-career-location="{{ $career->location }}" data-career-salary="{{ $career->salary_per_month }}" data-career-description="{{ $career->title_description }}" data-career-id="{{ $career->id }}">Apply Now<i class="flaticon-right-up"></i></button>
|
||||
<button type="button" class="build_button apply-now-button" data-bs-toggle="modal" data-bs-target="#applyInternshipModal" data-job-id="{{ $career->id }}" data-job-type="career" data-career-title="{{ $career->title }}" data-career-location="{{ $career->location }}" data-career-salary="{{ $career->salary_per_month }}" data-career-description="{{ $career->title_description }}">Apply Now<i class="flaticon-right-up"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
@@ -59,114 +59,77 @@
|
||||
</div>
|
||||
<!-- Pricing Plan Area End -->
|
||||
|
||||
<!-- Application Modal -->
|
||||
<div class="modal fade" id="applicationModal" tabindex="-1" aria-labelledby="applicationModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content rounded-3">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="applicationModalLabel">Apply for <span id="jobTitle"></span></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h6 id="jobLocation"></h6>
|
||||
<p id="jobSalary"></p>
|
||||
<p id="jobDescription"></p>
|
||||
<form id="applicationForm" enctype="multipart/form-data" action="{{ route('applications.store') }}" method="POST">
|
||||
@csrf
|
||||
<input type="hidden" name="career_id" id="careerId">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="name" class="form-label">Name <span> *</span></label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="birthdate" class="form-label">Birthdate <span> *</span></label>
|
||||
<input type="date" class="form-control" id="birthdate" name="birthdate" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="email" class="form-label">Email <span> *</span></label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="phone_number" class="form-label">Phone Number <span> *</span></label>
|
||||
<input type="text" class="form-control" id="phone_number" name="phone_number" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="resume_file" class="form-label">Resume (PDF, DOC, DOCX) <span> *</span></label>
|
||||
<input type="file" class="form-control" id="resume_file" name="resume_file" accept=".pdf,.doc,.docx" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="cover_letter" class="form-label">Cover Letter (Optional)</label>
|
||||
<textarea class="form-control" id="cover_letter" name="cover_letter" rows="5"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit Application</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
{{-- Application Modal --}}
|
||||
@include('web.components.application_modal', ['jobId' => null, 'jobType' => 'career']) {{-- jobId will be set by JS from button data attributes --}}
|
||||
|
||||
@push('footer-js')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var applicationModal = document.getElementById('applicationModal');
|
||||
applicationModal.addEventListener('show.bs.modal', function (event) {
|
||||
var button = event.relatedTarget;
|
||||
var careerTitle = button.getAttribute('data-career-title');
|
||||
var careerLocation = button.getAttribute('data-career-location');
|
||||
var careerSalary = button.getAttribute('data-career-salary');
|
||||
var careerDescription = button.getAttribute('data-career-description');
|
||||
var careerId = button.getAttribute('data-career-id');
|
||||
var applicationModal = document.getElementById('applyInternshipModal');
|
||||
if (applicationModal) {
|
||||
applicationModal.addEventListener('show.bs.modal', function (event) {
|
||||
var button = event.relatedTarget; // Button that triggered the modal
|
||||
var jobId = button.getAttribute('data-job-id'); // Generic attribute for job ID
|
||||
var jobType = button.getAttribute('data-job-type'); // Generic attribute for job type
|
||||
|
||||
var modalTitle = applicationModal.querySelector('#jobTitle');
|
||||
var modalLocation = applicationModal.querySelector('#jobLocation');
|
||||
var modalSalary = applicationModal.querySelector('#jobSalary');
|
||||
var modalDescription = applicationModal.querySelector('#jobDescription');
|
||||
var modalCareerId = applicationModal.querySelector('#careerId');
|
||||
var modalTitle = applicationModal.querySelector('#jobTitle');
|
||||
var modalLocation = applicationModal.querySelector('#jobLocation');
|
||||
var modalSalary = applicationModal.querySelector('#jobSalary');
|
||||
var modalDescription = applicationModal.querySelector('#jobDescription');
|
||||
var jobIdInput = applicationModal.querySelector('#jobIdInput');
|
||||
var applicationForm = applicationModal.querySelector('#applicationForm');
|
||||
|
||||
modalTitle.textContent = careerTitle;
|
||||
modalLocation.textContent = 'Location: ' + careerLocation;
|
||||
modalSalary.textContent = 'Salary: ' + careerSalary + ' / Per monthly';
|
||||
modalDescription.textContent = careerDescription;
|
||||
modalCareerId.value = careerId;
|
||||
});
|
||||
// Set dynamic values
|
||||
modalTitle.textContent = button.getAttribute('data-' + jobType + '-title');
|
||||
modalLocation.textContent = 'Location: ' + button.getAttribute('data-' + jobType + '-location');
|
||||
modalSalary.textContent = 'Salary: ' + button.getAttribute('data-' + jobType + '-salary') + ' / Per monthly';
|
||||
modalDescription.textContent = button.getAttribute('data-' + jobType + '-description');
|
||||
jobIdInput.value = jobId;
|
||||
|
||||
// Handle form submission with AJAX
|
||||
document.getElementById('applicationForm').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
let form = e.target;
|
||||
let formData = new FormData(form);
|
||||
|
||||
fetch(form.action, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
// Set form action dynamically
|
||||
if (jobType === 'internship') {
|
||||
applicationForm.action = '{{ route('internship.store') }}';
|
||||
jobIdInput.name = 'internship_id';
|
||||
} else if (jobType === 'career') {
|
||||
applicationForm.action = '{{ route('applications.store') }}'; // Assuming careers still use applications.store
|
||||
jobIdInput.name = 'career_id';
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.message) {
|
||||
alert(data.message);
|
||||
var modal = bootstrap.Modal.getInstance(applicationModal);
|
||||
modal.hide();
|
||||
form.reset();
|
||||
} else {
|
||||
alert('Error: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An error occurred. Please try again.');
|
||||
});
|
||||
});
|
||||
|
||||
// Handle form submission with AJAX
|
||||
document.getElementById('applicationForm').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
let form = e.target;
|
||||
let formData = new FormData(form);
|
||||
|
||||
fetch(form.action, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.message) {
|
||||
alert(data.message);
|
||||
var modal = bootstrap.Modal.getInstance(applicationModal);
|
||||
modal.hide();
|
||||
form.reset();
|
||||
} else {
|
||||
alert('Error: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An error occurred. Please try again.');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,32 @@
|
||||
@extends('web.layouts.app')
|
||||
|
||||
@section('title', $career->title)
|
||||
|
||||
@section('content')
|
||||
<!-- Main Content for Single Career Page -->
|
||||
<div class="container">
|
||||
<h1>{{ $career->title }}</h1>
|
||||
<p><strong>{{ __('Location:') }}</strong> {{ $career->location }}</p>
|
||||
<p><strong>{{ __('Salary:') }}</strong> {{ $career->salary_per_month }} {{ $career->salary_currency }}</p>
|
||||
|
||||
<h2>{{ __('Description') }}</h2>
|
||||
<p>{{ $career->title_description }}</p>
|
||||
|
||||
@if ($career->bullets)
|
||||
<h3>{{ __('Responsibilities and Qualifications') }}</h3>
|
||||
<ul>
|
||||
@foreach ($career->bullets as $bullet)
|
||||
<li>{{ $bullet['bullet'] }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
<!-- Apply Button - Triggers Modal -->
|
||||
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#applyInternshipModal">
|
||||
{{ __('Apply for this Career') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Application Modal -->
|
||||
@include('web.components.application_modal', ['jobId' => $career->id, 'jobType' => 'career'])
|
||||
@endsection
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
@extends('web.layouts.app')
|
||||
|
||||
@push('header-css')
|
||||
<style>
|
||||
#applicationForm > label > span {
|
||||
color: var(--gujurly-primary);
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<!-- Breadcrumb Area Start -->
|
||||
<div class="breadcrumb__area" style="background-image: url('/web/assets/img/page/breadcrumb.jpg');">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="breadcrumb__area-content">
|
||||
<h2>Internships</h2>
|
||||
<ul>
|
||||
<li><a href="/">Home</a><i class="fa-regular fa-angle-right"></i></li>
|
||||
<li>Internships</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Breadcrumb Area End -->
|
||||
<!-- Pricing Plan Area Start -->
|
||||
<div class="price__area section-padding">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-md-6 xl-mb-25 wow fadeInUp" data-wow-delay=".4s">
|
||||
@forelse ($internships as $internship)
|
||||
<div class="price__area-item">
|
||||
<div class="price__area-item-price">
|
||||
<span>{{ $internship->title }}</span>
|
||||
<h3>{{ $internship->location }}</h3>
|
||||
<h2>{{ $internship->salary_per_month }} {{ $internship->salary_currency }}</h2>
|
||||
<span>Per monthly</span>
|
||||
</div>
|
||||
<div class="price__area-item-list">
|
||||
<ul>
|
||||
@foreach($internship->bullets as $bullet)
|
||||
<li><i class="flaticon-checked"></i>{{ $bullet['bullet'] ?? '' }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
<div class="price__area-item-btn">
|
||||
<button type="button" class="build_button apply-now-button" data-bs-toggle="modal" data-bs-target="#applyInternshipModal" data-job-id="{{ $internship->id }}" data-job-type="internship" data-internship-title="{{ $internship->title }}" data-internship-location="{{ $internship->location }}" data-internship-salary="{{ $internship->salary_per_month }}" data-internship-description="{{ $internship->title_description }}">Apply Now<i class="flaticon-right-up"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<span>No internships found...</span>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Pricing Plan Area End -->
|
||||
|
||||
{{-- Application Modal --}}
|
||||
@include('web.components.application_modal', ['jobId' => null, 'jobType' => 'internship']) {{-- jobId will be set by JS from button data attributes --}}
|
||||
|
||||
@endsection
|
||||
|
||||
@push('footer-js')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var applicationModal = document.getElementById('applyInternshipModal');
|
||||
if (applicationModal) {
|
||||
applicationModal.addEventListener('show.bs.modal', function (event) {
|
||||
var button = event.relatedTarget; // Button that triggered the modal
|
||||
var jobId = button.getAttribute('data-job-id'); // Generic attribute for job ID
|
||||
var jobType = button.getAttribute('data-job-type'); // Generic attribute for job type
|
||||
|
||||
var modalTitle = applicationModal.querySelector('#jobTitle');
|
||||
var modalLocation = applicationModal.querySelector('#jobLocation');
|
||||
var modalSalary = applicationModal.querySelector('#jobSalary');
|
||||
var modalDescription = applicationModal.querySelector('#jobDescription');
|
||||
var jobIdInput = applicationModal.querySelector('#jobIdInput');
|
||||
var applicationForm = applicationModal.querySelector('#applicationForm');
|
||||
|
||||
// Set dynamic values
|
||||
modalTitle.textContent = button.getAttribute('data-' + jobType + '-title');
|
||||
modalLocation.textContent = 'Location: ' + button.getAttribute('data-' + jobType + '-location');
|
||||
modalSalary.textContent = 'Salary: ' + button.getAttribute('data-' + jobType + '-salary') + ' / Per monthly';
|
||||
modalDescription.textContent = button.getAttribute('data-' + jobType + '-description');
|
||||
jobIdInput.value = jobId;
|
||||
|
||||
// Set form action dynamically
|
||||
if (jobType === 'internship') {
|
||||
applicationForm.action = '{{ route('internship.store') }}';
|
||||
jobIdInput.name = 'internship_id';
|
||||
} else if (jobType === 'career') {
|
||||
applicationForm.action = '{{ route('applications.store') }}'; // Assuming careers still use applications.store
|
||||
jobIdInput.name = 'career_id';
|
||||
}
|
||||
});
|
||||
|
||||
// Handle form submission with AJAX
|
||||
document.getElementById('applicationForm').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
let form = e.target;
|
||||
let formData = new FormData(form);
|
||||
|
||||
fetch(form.action, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.message) {
|
||||
alert(data.message);
|
||||
var modal = bootstrap.Modal.getInstance(applicationModal);
|
||||
modal.hide();
|
||||
form.reset();
|
||||
} else {
|
||||
alert('Error: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An error occurred. Please try again.');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,32 @@
|
||||
@extends('web.layouts.app')
|
||||
|
||||
@section('title', $internship->title)
|
||||
|
||||
@section('content')
|
||||
<!-- Main Content for Single Internship Page -->
|
||||
<div class="container">
|
||||
<h1>{{ $internship->title }}</h1>
|
||||
<p><strong>{{ __('Location:') }}</strong> {{ $internship->location }}</p>
|
||||
<p><strong>{{ __('Salary:') }}</strong> {{ $internship->salary_per_month }} {{ $internship->salary_currency }}</p>
|
||||
|
||||
<h2>{{ __('Description') }}</h2>
|
||||
<p>{{ $internship->title_description }}</p>
|
||||
|
||||
@if ($internship->bullets)
|
||||
<h3>{{ __('Responsibilities and Qualifications') }}</h3>
|
||||
<ul>
|
||||
@foreach ($internship->bullets as $bullet)
|
||||
<li>{{ $bullet['bullet'] }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
<!-- Apply Button - Triggers Modal -->
|
||||
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#applyInternshipModal">
|
||||
{{ __('Apply for this Internship') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Application Modal -->
|
||||
@include('web.components.application_modal', ['jobId' => $internship->id, 'jobType' => 'internship'])
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user