Entrypoint: Add Application Page

This commit finally adds the dynamically rendered form that changes according to how the user builds their form.
It also fragments the header and footer for the main page into their own separate files for ease of access later.
Vacancy status has also been added to the Vacancies in DB.
All staff application endpoints have also been moved to under the user application endpoints group, for ease of use (duplicated route group).
This commit is contained in:
Miguel Nogueira 2020-05-08 06:06:24 +01:00
parent 49c1ed4698
commit 4c6a435e34
11 changed files with 318 additions and 121 deletions

View File

@ -16,6 +16,6 @@ class Form extends Model
public function vacancy() public function vacancy()
{ {
return $this->hasMany('App\Vacancy', 'vacancyFormID'); return $this->hasMany('App\Vacancy');
} }
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Vacancy;
use Illuminate\Http\Request; use Illuminate\Http\Request;
class ApplicationController extends Controller class ApplicationController extends Controller
@ -36,4 +37,26 @@ class ApplicationController extends Controller
{ {
return view('dashboard.appmanagement.interview'); return view('dashboard.appmanagement.interview');
} }
public function renderApplicationForm(Request $request, $vacancySlug)
{
$vacancyWithForm = Vacancy::with('forms')->where('vacancySlug', $vacancySlug)->get();
if (!$vacancyWithForm->isEmpty())
{
return view('dashboard.application-rendering.apply')
->with([
'vacancy' => $vacancyWithForm->first(),
'preprocessedForm' => json_decode($vacancyWithForm->first()->forms->formStructure, true)
]);
}
else
{
abort(404, 'We\'re ssssorry, but the application form you\'re looking for could not be found.');
}
}
} }

View File

@ -6,6 +6,7 @@ use App\Form;
use App\Http\Requests\VacancyRequest; use App\Http\Requests\VacancyRequest;
use App\Vacancy; use App\Vacancy;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Str;
class VacancyController extends Controller class VacancyController extends Controller
{ {
@ -28,6 +29,7 @@ class VacancyController extends Controller
'vacancyName' => $request->vacancyName, 'vacancyName' => $request->vacancyName,
'vacancyDescription' => $request->vacancyDescription, 'vacancyDescription' => $request->vacancyDescription,
'vacancySlug' => Str::slug($request->vacancyName),
'permissionGroupName' => $request->permissionGroup, 'permissionGroupName' => $request->permissionGroup,
'discordRoleID' => $request->discordRole, 'discordRoleID' => $request->discordRole,
'vacancyFormID' => $request->vacancyFormID, 'vacancyFormID' => $request->vacancyFormID,

View File

@ -16,13 +16,14 @@ class Vacancy extends Model
'discordRoleID', 'discordRoleID',
'vacancyFormID', 'vacancyFormID',
'vacancyCount', 'vacancyCount',
'vacancyStatus' 'vacancyStatus',
'vacancySlug'
]; ];
public function forms() public function forms()
{ {
return $this->belongsTo('App\Form'); return $this->belongsTo('App\Form', 'vacancyFormID', 'id');
} }
public function open() public function open()

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddSlugToVacancy extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('vacancies', function (Blueprint $table) {
$table->string('vacancySlug')->after('vacancyDescription');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('vacancies', function (Blueprint $table) {
$table->dropColumn('vacancySlug');
});
}
}

View File

@ -1,99 +1,7 @@
<!doctype HTML> @include('breadcrumbs.header')
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="The Minecraft Staff Member Management Tool">
<meta name="author" content="Miguel Nogueira">
<meta name="tags" content="minecraft, minecraft server staff, minecraft staff, minecraft servers">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
<!-- Google Fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.16.0/css/mdb.min.css" rel="stylesheet">
<link href="https:////cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet">
<link href="/app.css" rel="stylesheet">
<!-- JQuery -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- Bootstrap tooltips -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.4/umd/popper.min.js"></script>
<!-- Bootstrap core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
<!-- MDB core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.16.0/js/mdb.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<!--Main Navigation-->
<header>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark">
<a class="navbar-brand" href="#"><strong>Raspberry Network</strong></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link " href="#">Homepage</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Ban Appeals</a>
</li>
</ul>
</div>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ml-auto float-right">
<li class="nav-item">
<a class="nav-link" href="#">Application Status</a>
</li>
<li class="nav-item">
<a class="nav-link" href="login">Sign-in</a>
</li>
<li class="nav-item">
<a class="nav-link" href="register">Register</a>
</li>
</ul>
</div>
</nav>
<div class="view intro-2">
<div class="full-bg-img">
<div class="mask rgba-black-light flex-center">
<div class="container text-center white-text">
<div class="white-text text-center wow fadeInUp">
<h2>Raspberry Network Application Center</h2>
<h5>Welcome to our team management center!</h5>
<br>
<p>Here, you can apply for open staff member positions, view your application status, and manage your profile. </p>
<p>Sign up with Twitch or Email to continue.</p>
</div>
</div>
</div>
</div>
</div>
</header>
<!--Main Navigation-->
<body> <body>
<!-- This section is global -->
@if (session()->has('error')) @if (session()->has('error'))
<script> <script>
@ -110,19 +18,8 @@
@yield('content') @yield('content')
@include('breadcrumbs.footer')
<!-- Footer -->
<footer class="page-footer font-small footer-grad">
<!-- Copyright -->
<div class="footer-copyright text-center py-3">
<a href="https://spacejewel-hosting.com/"> Spacejewel Hosting &copy; 2019-2020 - All rights reserved</a>
</div>
<!-- Copyright -->
<!-- Built by Miguel Nogueira -->
</footer>
<!-- Footer -->
</body> </body>
</html> </html>

View File

@ -0,0 +1,12 @@
<!-- Footer -->
<footer class="page-footer font-small footer-grad">
<!-- Copyright -->
<div class="footer-copyright text-center py-3">
<a href="https://spacejewel-hosting.com/"> Spacejewel Hosting &copy; 2019-2020 - All rights reserved</a>
</div>
<!-- Copyright -->
<!-- Built by Miguel Nogueira -->
</footer>
<!-- Footer -->

View File

@ -0,0 +1,106 @@
<!doctype HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="The Minecraft Staff Member Management Tool">
<meta name="author" content="Miguel Nogueira">
<meta name="tags" content="minecraft, minecraft server staff, minecraft staff, minecraft servers">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
<!-- Google Fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.16.0/css/mdb.min.css" rel="stylesheet">
<link href="https:////cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet">
<link href="/app.css" rel="stylesheet">
<!-- JQuery -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- Bootstrap tooltips -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.4/umd/popper.min.js"></script>
<!-- Bootstrap core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
<!-- MDB core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.16.0/js/mdb.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<!--Main Navigation-->
<header>
<nav class="navbar fixed-top navbar-expand-lg navbar-dark">
<a class="navbar-brand" href="#"><strong>Raspberry Network</strong></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link " href="#">Homepage</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Ban Appeals</a>
</li>
</ul>
</div>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ml-auto float-right">
@guest
<li class="nav-item">
<button class="btn btn-info" type="button" onclick="window.location.href='login'"><i class="fas fa-sign-in-alt"></i> Sign-in</button>
</li>
<li class="nav-item">
<button class="btn btn-info" type="button" onclick="window.location.href='register'"><i class="fas fa-plus"></i> Sign-up</button>
</li>
@endguest
@auth
<li class="nav-item">
<button type="button" class="btn btn-info" onclick="window.location.href='dashboard'">Dashboard</button>
</li>
<li class="nav-item">
<form method="POST" action="logout">
@csrf
<button type="submit" class="btn btn-danger"><i class="fa fa-power-off"></i> Sign-out</button>
</form>
</li>
@endauth
</ul>
</div>
</nav>
<div class="view intro-2">
<div class="full-bg-img">
<div class="mask rgba-black-light flex-center">
<div class="container text-center white-text">
<div class="white-text text-center wow fadeInUp">
<h2>Raspberry Network Application Center</h2>
<h5>Welcome to our team management center!</h5>
<br>
<p>Here, you can apply for open staff member positions, view your application status, and manage your profile. </p>
<p>Sign up with Twitch or Email to continue.</p>
</div>
</div>
</div>
</div>
</div>
</header>

View File

@ -0,0 +1,115 @@
@extends('adminlte::page')
@section('title', 'Raspberry Network Team Management')
@section('content_header')
<h1>My Account / Apply / {{$vacancy->vacancyName}} Application</h1>
@stop
@section('content')
<div class="modal fade" tabindex="-1" id="confirm" role="dialog" aria-labelledby="modalConfirmLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalConfirmLabel">Please confirm</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Are you sure you want to submit your application? Please review each of your answers carefully before doing so.</p>
<p class="text-bold">Please note: Applications CANNOT be modified once they're submitted!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success"><i class="fas fa-check-double"></i> Accept & Send</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Review</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="callout callout-success">
<p class="text-bold">You are applying for: {{$vacancy->vacancyName}}</p>
<p>We're glad you've decided to apply. Generally, applications take 48 hours to be processed and reviewed. Depending on the circumstances and the volume of applications, you may receive an answer in a shorter time.</p>
<p>Please fill out the form below. Keep all answers concise and complete. Please keep in mind that the age requirement is <b>at least 18 years old</b>.</p>
<p class="text-bold">Asking about your application will result in instant denial. Everything you need to know is here.</p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="card">
<div class="card-header">
<div class="card-title"><h4>{{$vacancy->forms->formName}}</h4></div>
</div>
<div class="card-body">
@foreach($preprocessedForm['fields'] as $fieldName => $field)
@switch ($field['type'])
@case('textarea')
<div class="form-group mt-2 mb-2">
<label for="{{$fieldName}}">{{$field['title']}}</label>
<textarea class="form-control" rows="7" name="{{$fieldName}}" id="{{$fieldName}}">
</textarea>
</div>
@break
@case('textbox')
<div class="form-group mt-2 mb-2">
<label for="{{$fieldName}}">{{$field['title']}}</label>
<input type="text" name="{{$fieldName}}" id="{{$fieldName}}" class="form-control">
</div>
@break
@endswitch
@endforeach
</div>
<div class="card-footer text-center">
<button type="button" class="btn btn-success" onclick="$('#confirm').modal('show')"><i class="fas fa-paper-plane"></i> Send</button>
</div>
</div>
</div>
</div>
@stop

View File

@ -30,7 +30,11 @@
<div class="card-header text-center"> <div class="card-header text-center">
<h4 class="card-title">{{$position->vacancyName}}</h4> <h4 class="card-title">{{$position->vacancyName}}</h4>
@if ($position->vacancyCount == 1)
<p class="card-subtitle">There is <span class="badge badge-success">{{$position->vacancyCount}}</span> open position!</p>
@else
<p class="card-subtitle">There are <span class="badge badge-success">{{$position->vacancyCount}}</span> open positions!</p>
@endif
</div> </div>
@ -45,8 +49,7 @@
<div class="card-footer text-center"> <div class="card-footer text-center">
<button type="button" class="btn btn-success">Apply</button> <button type="button" class="btn btn-success" onclick="window.location.href='{{route('renderApplicationForm', ['vacancySlug' => $position->vacancySlug])}}'">Apply</button>
<button type="button" class="btn btn-info">Learn More</button>
</div> </div>

View File

@ -32,15 +32,6 @@ Route::group(['middleware' => 'auth'], function(){
Route::get('/approved', 'ApplicationController@showApprovedApps') Route::get('/approved', 'ApplicationController@showApprovedApps')
->name('userApprovedApps'); ->name('userApprovedApps');
});
Route::group(['prefix' => '/profile'], function (){
Route::get('/settings', 'ProfileController@index');
});
Route::group(['prefix' => '/applications'], function (){
Route::get('/staff/outstanding', 'ApplicationController@showAllPendingApps') Route::get('/staff/outstanding', 'ApplicationController@showAllPendingApps')
->name('staffPendingApps'); ->name('staffPendingApps');
@ -51,8 +42,23 @@ Route::group(['middleware' => 'auth'], function(){
Route::get('/staff/pending-interview', 'ApplicationController@showPendingInterview') Route::get('/staff/pending-interview', 'ApplicationController@showPendingInterview')
->name('pendingInterview'); ->name('pendingInterview');
}); });
Route::group(['prefix' => 'apply'], function (){
Route::get('positions/{vacancySlug}', 'ApplicationController@renderApplicationForm')
->name('renderApplicationForm');
});
Route::group(['prefix' => '/profile'], function (){
Route::get('/settings', 'ProfileController@index');
});
Route::group(['prefix' => '/hr'], function (){ Route::group(['prefix' => '/hr'], function (){
Route::get('staff-members', 'UserController@showStaffMembers') Route::get('staff-members', 'UserController@showStaffMembers')