diff --git a/README.md b/README.md index fb4bae8a..b6b8106d 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ docker run --rm \ ``` 4. Install the NPM packages - `npm install` 5. Set up the environment variables - `cp .env.example .env` -6. Add the app key - `./vendor/bin/sail artisan key:generate` -7. After the dependencies are installed run `./vendor/bin/sail up -d` +6. After the dependencies are installed run `./vendor/bin/sail up -d` +7. Add the app key - `./vendor/bin/sail artisan key:generate` 8. After the creation of the containers run `./vendor/bin/sail artisan migrate` 9. Run `npm run dev` diff --git a/app/Actions/Users/AddParticipantToCompanyHandler.php b/app/Actions/Users/AddParticipantToCompanyHandler.php new file mode 100644 index 00000000..b03b0c2c --- /dev/null +++ b/app/Actions/Users/AddParticipantToCompanyHandler.php @@ -0,0 +1,54 @@ +company) { + throw new Exception('The user is already a member of a company. Are you sure this is the right user?'); + } + + $user->update([ + 'company_id' => $company->id + ]); + + if ($user->presenter_of) { + if (!$company->has_presentations_left) { + throw new Exception('The company has reached their presentation limit. Contact them to resolve this.'); + } + + $presentation = $user->presenter_of; + $presentation->update([ + 'company_id' => $company->id + ]); + } else { + if (!Role::findByName($role, 'web')) { + throw new Exception('The role cannot be found'); + } + + $role = Role::findByName($role, 'web'); + $user->assignRole($role); + } + }); + } +} diff --git a/app/Console/Commands/AddParticipantToCompany.php b/app/Console/Commands/AddParticipantToCompany.php new file mode 100644 index 00000000..8446cc5b --- /dev/null +++ b/app/Console/Commands/AddParticipantToCompany.php @@ -0,0 +1,46 @@ +withoutLogs(function () { + try { + $user = User::where('email', $this->argument('email'))->firstOrFail(); + $company = Company::findOrFail($this->argument('company_id')); + + (new AddParticipantToCompanyHandler())->execute($user, $company, $this->argument('role')); + + $user->refresh(); + $this->info("You successfully added {$user->email} as part of the {$user->company->name}"); + } catch (\Exception $e) { + $this->error($e); + } + }); + } +} diff --git a/app/Http/Controllers/Crew/BoothController.php b/app/Http/Controllers/Crew/BoothController.php index 1060a6b9..32f5c48d 100644 --- a/app/Http/Controllers/Crew/BoothController.php +++ b/app/Http/Controllers/Crew/BoothController.php @@ -43,6 +43,9 @@ public function create() */ public function store(Request $request) { + // CURRENTLY NOT IN USE + abort(404); + if ($request->user()->cannot('create', Booth::class)) { abort(403); } @@ -77,17 +80,13 @@ public function show(Booth $booth) /** * Approve or reject the specified resource in storage. */ - public function approve(Request $request, Booth $booth) + public function approve(Booth $booth, bool $isApproved) { if (Auth::user()->cannot('approveRequest', $booth)) { abort(403); } - $validated = $request->validate([ - 'approved' => 'required|boolean' - ]); - - $isApproved = $validated['approved']; + $isApproved = filter_var($isApproved, FILTER_VALIDATE_BOOLEAN); $booth->handleApproval($isApproved); $template = $isApproved ? 'You approved the booth of :company!' diff --git a/app/Http/Controllers/Crew/CompanyController.php b/app/Http/Controllers/Crew/CompanyController.php index 8ec69b4c..d61c157f 100644 --- a/app/Http/Controllers/Crew/CompanyController.php +++ b/app/Http/Controllers/Crew/CompanyController.php @@ -92,17 +92,14 @@ public function show(Company $company): View /** * Approve or reject the specified resource in storage. */ - public function approve(Request $request, Company $company) + public function approve(Company $company, bool $isApproved) { if (Auth::user()->cannot('approveRequest', $company)) { abort(403); } - $validated = $request->validate([ - 'approved' => 'required|boolean' - ]); - $isApproved = $validated['approved']; + $isApproved = filter_var($isApproved, FILTER_VALIDATE_BOOLEAN); if (!$isApproved) { if ($company->representative->receive_emails) { Mail::to($company->representative->email)->send(new CompanyDisapprovedMailable($company)); @@ -203,7 +200,7 @@ private function createCompanyWithNewUser($input) 'email' => $input['rep_new_email'], 'role' => 'company representative', ]); - + Mail::to($input['rep_new_email'])->send(new CompanyRepInvitation($invitation)); return $company; diff --git a/app/Http/Controllers/Crew/CrewController.php b/app/Http/Controllers/Crew/CrewController.php index ce2c0d46..7b59faa1 100644 --- a/app/Http/Controllers/Crew/CrewController.php +++ b/app/Http/Controllers/Crew/CrewController.php @@ -17,7 +17,7 @@ class CrewController extends Controller * Returns the main page of the crew page * @return View */ - public function index() : View + public function index(): View { if (!Gate::authorize('view-crew')) { abort(403); @@ -25,7 +25,14 @@ public function index() : View $roles = Role::whereNotIn( 'name', - ['participant', 'company representative', 'company member', 'booth owner'] + [ + 'participant', + 'company representative', + 'company member', + 'booth owner', + 'pending booth owner', + 'pending speaker' + ] )->get(); return view('crew.crew.index', compact('roles')); diff --git a/app/Http/Controllers/Crew/PresentationController.php b/app/Http/Controllers/Crew/PresentationController.php index c9bfa079..33dfe0a1 100644 --- a/app/Http/Controllers/Crew/PresentationController.php +++ b/app/Http/Controllers/Crew/PresentationController.php @@ -96,17 +96,13 @@ public function show(Presentation $presentation): View /** * Approve or reject the specified resource in storage. */ - public function approve(Request $request, Presentation $presentation) + public function approve(Presentation $presentation, bool $isApproved) { if (Auth::user()->cannot('approve', $presentation)) { abort(403); } - $validated = $request->validate([ - 'approved' => 'required|boolean' - ]); - - $isApproved = $validated['approved']; + $isApproved = filter_var($isApproved, FILTER_VALIDATE_BOOLEAN); if (!$isApproved) { foreach ($presentation->speakers as $speaker) { if ($speaker->receive_emails) { diff --git a/app/Http/Controllers/Crew/RoomController.php b/app/Http/Controllers/Crew/RoomController.php index 9e3c0eab..87695f43 100644 --- a/app/Http/Controllers/Crew/RoomController.php +++ b/app/Http/Controllers/Crew/RoomController.php @@ -81,7 +81,7 @@ public function show(Room $room) */ public function destroy(Room $room): RedirectResponse // TODO: Refactor the FK constraints in the db { - if (Auth::user()->cannot('delete', Room::class)) { + if (Auth::user()->cannot('delete', $room)) { abort(403); } diff --git a/app/Http/Controllers/Crew/SponsorshipController.php b/app/Http/Controllers/Crew/SponsorshipController.php index de23daec..2860e113 100644 --- a/app/Http/Controllers/Crew/SponsorshipController.php +++ b/app/Http/Controllers/Crew/SponsorshipController.php @@ -98,17 +98,13 @@ public function show(Company $company): View * @param Company $company * @return mixed */ - public function approve(Request $request, Company $company) + public function approve(Company $company, bool $isApproved) { if (Auth::user()->cannot('approve', Sponsorship::class)) { abort(403); } - $validated = $request->validate([ - 'approved' => 'required|boolean' - ]); - - $isApproved = $validated['approved']; + $isApproved = filter_var($isApproved, FILTER_VALIDATE_BOOLEAN); $company->handleSponsorshipApproval($isApproved); $template = $isApproved ? 'You approved the sponsorship of :company!' diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 4d0810a1..5e9e6701 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -4,6 +4,7 @@ use App\Models\Edition; use App\Models\Company; +use App\Models\Sponsorship; use Illuminate\Http\Request; use Illuminate\View\View; @@ -16,11 +17,12 @@ class HomeController extends Controller public function index() : View { $edition = Edition::current(); + $anySponsorships = Sponsorship::doesntHave('companies')->count() === Sponsorship::count(); $goldSponsorCompany = Company::where('is_approved', 1) ->where('sponsorship_id', 1) ->where('is_sponsorship_approved', 1) ->first(); - return view('welcome', compact(['edition', 'goldSponsorCompany'])); + return view('welcome', compact(['edition', 'goldSponsorCompany', 'anySponsorships'])); } } diff --git a/app/Http/Controllers/ProgrammeController.php b/app/Http/Controllers/ProgrammeController.php index bc1eff81..ff9c852b 100644 --- a/app/Http/Controllers/ProgrammeController.php +++ b/app/Http/Controllers/ProgrammeController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Models\Edition; use App\Models\Presentation; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -16,6 +17,10 @@ class ProgrammeController extends Controller */ public function index(): View { + if (!optional(Edition::current())->is_programme_released) { + abort(404); + } + $lectures = Presentation::where('type', 'lecture') ->whereNotNull('room_id') ->whereNotNull('timeslot_id') @@ -47,6 +52,10 @@ public function index(): View */ public function show(Presentation $presentation): View { + if (!$presentation->is_approved) { + abort(404); + } + $styles = [ 1 => [ 'borderColor' => 'bg-gradient-to-r from-yellow-300 to-yellow-600', // Gold diff --git a/app/Http/Controllers/SpeakerController.php b/app/Http/Controllers/SpeakerController.php index 5f7494a7..ad688bb8 100644 --- a/app/Http/Controllers/SpeakerController.php +++ b/app/Http/Controllers/SpeakerController.php @@ -12,29 +12,34 @@ class SpeakerController extends Controller */ public function index() { - $speakers = collect(); $edition = Edition::current(); + $query = UserPresentation::where('role', 'speaker'); if (!$edition) { return redirect(route('welcome')) ->dangerBanner("Speakers are not available yet."); } + // If the final program is released, filter by room_id and timeslot_id if (optional(Edition::current())->is_final_programme_released) { - $speakers = UserPresentation::where('role', 'speaker') - ->whereHas('presentation', function ($query) { - $query->whereNotNull('room_id') - ->whereNotNull('timeslot_id'); - }) - ->get() - ->sortBy(function ($speaker) { - if ($speaker->user->company && $speaker->user->company->is_sponsorship_approved) { - return $speaker->user->company->sponsorship_id; - } - return 999; // Assign a high value to non-sponsored speakers - }); + $query->whereHas('presentation', function ($query) { + $query->whereNotNull('room_id') + ->whereNotNull('timeslot_id'); + }); + } else { + // Otherwise, filter by is_approved + $query->whereHas('presentation', function ($query) { + $query->where('is_approved', true); + }); } + $speakers = $query->get()->sortBy(function ($speaker) { + if ($speaker->user->company && $speaker->user->company->is_sponsorship_approved) { + return $speaker->user->company->sponsorship_id; + } + return 999; // Assign a high value to non-sponsored speakers + }); + return view('speakers.index', compact('speakers', 'edition')); } } diff --git a/app/Livewire/Booth/CreateBooth.php b/app/Livewire/Booth/CreateBooth.php new file mode 100644 index 00000000..5e7ee566 --- /dev/null +++ b/app/Livewire/Booth/CreateBooth.php @@ -0,0 +1,142 @@ +companies = Company::whereDoesntHave('booth')->where('is_approved', '=', '1')->get(); + $this->company = $this->companies->first(); + $this->isDropdownVisible = false; + $this->users = optional($this->company)->users; + $this->searchValue = ''; + } + + /** + * Creates the entity + * @return void + */ + public function save() + { + $this->validate(); + + $this->validate([ + 'company' => 'required', + 'selectedUser' => 'required' + ]); + + $boothData = [ + 'width' => $this->width, + 'length' => $this->length, + 'additional_information' => $this->additionalInformation, + 'company_id' => $this->company->id, + 'is_approved' => true + ]; + + Booth::create($boothData); + + $this->selectedUser->assignRole('booth owner'); + + if ($this->selectedUser->hasRole('pending booth owner')) { + $this->selectedUser->removeRole('pending booth owner'); + } + + $this->redirect(route('moderator.booths.index')); + } + + /** + * Triggers the filtering function if the email/name is being changed + * + * @return void + */ + public function updatedSearchValue() : void + { + $this->users = $this->company->users; + if (!empty($this->searchValue)) { + $this->users = $this->users->filter(function ($user) { + $nameMatch = stripos($user->name, $this->searchValue) !== false; + $emailMatch = stripos($user->email, $this->searchValue) !== false; + + return $nameMatch || $emailMatch; + }); + } + } + + /** + * Handles the update of the company id + * @return void + */ + public function updatedCompanyId() : void + { + $this->company = Company::find($this->companyId); + $this->users = $this->company->users; + $this->searchValue = ''; + $this->updatedSearchValue(); + $this->selectedUser = null; + $this->isDropdownVisible = false; + } + + /** + * Triggered when the user chooses the assignee + * + * @param $id + * @return void + */ + public function selectUser($id) : void + { + $this->selectedUser = User::find($id); + $this->searchValue = $this->selectedUser->name; + $this->updatedSearchValue(); + $this->isDropdownVisible = false; + } + + /** + * Responsible for the visibility status of the dropdown + * + * @return void + */ + public function toggleDropdown() : void + { + $this->isDropdownVisible = !$this->isDropdownVisible; + } + + /** + * Renders the component + * @return View + */ + public function render() : View + { + return view('livewire.booth.create-booth'); + } +} diff --git a/app/Livewire/Company/AddMember.php b/app/Livewire/Company/AddMember.php index 0acbbf57..6adb7fb9 100644 --- a/app/Livewire/Company/AddMember.php +++ b/app/Livewire/Company/AddMember.php @@ -59,7 +59,7 @@ public function invite(): void $this->validate(); if ($this->currentRole == 'speaker') { $this->currentRole = 'pending speaker'; - } else if ($this->currentRole == 'booth owner') { + } elseif ($this->currentRole == 'booth owner') { $this->currentRole = 'pending booth owner'; } diff --git a/app/Livewire/Company/AddParticipant.php b/app/Livewire/Company/AddParticipant.php new file mode 100644 index 00000000..e464e697 --- /dev/null +++ b/app/Livewire/Company/AddParticipant.php @@ -0,0 +1,111 @@ +company = Company::find($companyId); + $this->searchValue = ''; + $this->defaultUsers = User::role('participant') + ->whereNull('company_id') + ->get() + ->filter(function ($user) { + return $user->hasExactRoles('participant'); + }); + $this->users = $this->defaultUsers; + $this->isDropdownVisible = false; + $this->canAssignRole = false; + $this->assignedRole = 'company member'; + } + + /** + * Triggers the filtering function if the email/name is being changed + * + * @return void + */ + public function updatedSearchValue(): void + { + $this->users = $this->defaultUsers; + if (!empty($this->searchValue)) { + $this->users = $this->users->filter(function ($user) { + $nameMatch = stripos($user->name, $this->searchValue) !== false; + $emailMatch = stripos($user->email, $this->searchValue) !== false; + + return $nameMatch || $emailMatch; + }); + } + } + + /** + * Assigns the participant to a company or handles the failure of assigning + * @return \Illuminate\Http\RedirectResponse|void + */ + public function save() + { + try { + (new AddParticipantToCompanyHandler())->execute($this->selectedUser, $this->company, $this->assignedRole); + return redirect()->to(route('moderator.companies.show', $this->company)); + } catch (Exception $exception) { + Toaster::error($exception->getMessage()); + } + } + + /** + * Triggered when the user chooses the assignee + * + * @param $id + * @return void + */ + public function selectUser($id): void + { + $this->selectedUser = User::find($id); + $this->searchValue = $this->selectedUser->name; + $this->updatedSearchValue(); + $this->isDropdownVisible = false; + + $this->canAssignRole = is_null($this->selectedUser->presenter_of); + } + + /** + * Responsible for the visibility status of the dropdown + * + * @return void + */ + public function toggleDropdown(): void + { + $this->isDropdownVisible = !$this->isDropdownVisible; + } + + /** + * Renders the component + * @return View + */ + public function render(): View + { + return view('livewire.company.add-participant'); + } +} diff --git a/app/Livewire/ConfirmationModal.php b/app/Livewire/ConfirmationModal.php new file mode 100644 index 00000000..c835c5ca --- /dev/null +++ b/app/Livewire/ConfirmationModal.php @@ -0,0 +1,26 @@ +logAll() - ->setDescriptionForEvent(fn(string $eventName) => "{$this->name} booth has been {$eventName} by " . Auth::user()->name) + ->setDescriptionForEvent(fn(string $eventName) => "Presentation {$this->name} has been {$eventName} by " . Auth::user()->name) ->logOnlyDirty() ->dontLogIfAttributesChangedOnly(['is_approved']); } diff --git a/app/Policies/CompanyPolicy.php b/app/Policies/CompanyPolicy.php index 5058f67d..f8dec845 100644 --- a/app/Policies/CompanyPolicy.php +++ b/app/Policies/CompanyPolicy.php @@ -111,6 +111,18 @@ public function viewAnyMember(User $user, Company $company): bool && $user->hasPermissionTo('viewAny company member'); } + /** + * Determine if the user can add company members. + * + * @param User $user The user instance. + * @param Company $company The company instance. + * @return bool + */ + public function addMember(User $user, Company $company): bool + { + return $user->hasPermissionTo('add company member'); + } + /** * Determine if the user can edit company members. * diff --git a/app/Policies/RoomPolicy.php b/app/Policies/RoomPolicy.php index fa23aeae..1c8952fb 100644 --- a/app/Policies/RoomPolicy.php +++ b/app/Policies/RoomPolicy.php @@ -2,6 +2,7 @@ namespace App\Policies; +use App\Models\Room; use App\Models\User; class RoomPolicy @@ -56,8 +57,12 @@ public function update(User $user): bool * @param User $user * @return bool */ - public function delete(User $user) + public function delete(User $user, Room $room) { - return $user->can('delete room'); + if (!$user->can('delete room')) { + return false; + } + + return $room->presentations->count() == 0 && $room->defaultPresentations->count() == 0; } } diff --git a/database/factories/CompanyFactory.php b/database/factories/CompanyFactory.php index de547d02..f56efe72 100644 --- a/database/factories/CompanyFactory.php +++ b/database/factories/CompanyFactory.php @@ -21,7 +21,7 @@ public function definition(): array { return [ 'name' => $this->faker->unique()->company(), - 'website' => 'www.example.com', + 'website' => 'https://www.example.com', 'description' => $this->faker->paragraph(), 'motivation' => $this->faker->paragraph(), 'phone_number' => $this->faker->phoneNumber, diff --git a/public/js/registration-validation.js b/public/js/registration-validation.js index ed5cf3f5..972c30b6 100644 --- a/public/js/registration-validation.js +++ b/public/js/registration-validation.js @@ -3,10 +3,6 @@ document.addEventListener("DOMContentLoaded", function() { const passwordRulesDiv = document.getElementById('password-rules'); const passwordInput = document.getElementById('password'); - if(document.getElementById('company_postcode')) { - postcodeValidation(); - } - //show password rules when user clicks on password field passwordInput.addEventListener('click', function () { passwordRulesDiv.classList.remove('hidden'); @@ -31,31 +27,6 @@ document.addEventListener("DOMContentLoaded", function() { passwordRulesDiv.classList.add('hidden'); }); - function postcodeValidation() { - document.getElementById('company_postcode').addEventListener('keydown', function(event) { - const position = document.getElementById('company_postcode').selectionStart; - const userInput = document.getElementById('company_postcode').value; - - if ( - event.key === 'Backspace' || - event.key === 'ArrowLeft' || - event.key === 'ArrowRight' || - event.key === 'ArrowUp' || - event.key === 'ArrowDown' || - event.key === 'Tab' - ) { - return; - } - - if ( - !((position < 4 && /[0-9]/.test(event.key)) || - (position >= 4 && position <= 5 && /[A-Za-z]/.test(event.key))) - ) { - event.preventDefault(); - } - }); - } - const emailInput = document.getElementById('email'); emailInput.addEventListener('blur', function() { diff --git a/resources/views/components/countdown.blade.php b/resources/views/components/countdown.blade.php index f9f54305..a7d05b7a 100644 --- a/resources/views/components/countdown.blade.php +++ b/resources/views/components/countdown.blade.php @@ -4,13 +4,18 @@ @push('scripts') - diff --git a/resources/views/crew/booths/index.blade.php b/resources/views/crew/booths/index.blade.php index 056c6339..c2ebbde9 100644 --- a/resources/views/crew/booths/index.blade.php +++ b/resources/views/crew/booths/index.blade.php @@ -11,41 +11,59 @@ - @forelse($booths as $index => $booth) - -
-
-
+ + + + + + + + + @forelse($booths as $index => $booth) + + + + + @empty + + + + @endforelse + +
+ Company Name + + Created At +
+
+
+ +
+ {{$booth->company->name}} +
+
+
+
+
-
- {{$booth->company->name}} -
+ {{ $booth->created_at->format('d/m/Y') }}
- -
- - {{$booth->created_at->format('d/m/Y')}} -
- - - @empty -

There are currently no new - booths waiting on approval.

- @endforelse - +
+ There are currently no booths. +
{{ $booths->links() }}
diff --git a/resources/views/crew/booths/show.blade.php b/resources/views/crew/booths/show.blade.php index fa7018cd..c464e77e 100644 --- a/resources/views/crew/booths/show.blade.php +++ b/resources/views/crew/booths/show.blade.php @@ -133,24 +133,36 @@ class="mt-1 text-sm leading-6 text-{{ $booth->is_approved ? 'green-500' : 'yello @if(!$booth->is_approved) @can('approveRequest', $booth) -
- @csrf - +
{{ __('Approve') }} - -
- @csrf - - + + {{ __('Reject') }} - -
+ +
@endcan @endif diff --git a/resources/views/crew/companies/create.blade.php b/resources/views/crew/companies/create.blade.php index f7d22b13..6a97fd7a 100644 --- a/resources/views/crew/companies/create.blade.php +++ b/resources/views/crew/companies/create.blade.php @@ -82,21 +82,27 @@ class="after:content-['*'] after:text-red-500 border-gray-300 dark:border-gray-7
+
- - - @foreach(User::forCompanyRep()->get() as $user) - - @endforeach - - or if they do not have an account yet - - +
+ If they have registered already: + + + @foreach(User::forCompanyRep()->get() as $user) + + @endforeach + +
+
+ or if they do not have an account yet: + + +
diff --git a/resources/views/crew/companies/index.blade.php b/resources/views/crew/companies/index.blade.php index fd43b0e0..258fcd23 100644 --- a/resources/views/crew/companies/index.blade.php +++ b/resources/views/crew/companies/index.blade.php @@ -10,26 +10,39 @@ {{ __('Invite a company') }} - - {{-- - {{__('Create a company')}} - --}} + + + + + + + + + @forelse($companies as $index => $company) - -
+
+ + + + @empty -

There are currently no new presentations waiting on approval.

+ + + @endforelse - + +
+ Company Name + + Company Representative + + Created At +
@if($company->logo_path) Logo of {{$company->name}} + src="{{ url('storage/'. $company->logo_path) }}" + alt="Logo of {{$company->name}}"> @else @@ -41,24 +54,36 @@
-
-
+ {{ optional($company->representative)->name }} + +
+ - {{$company->created_at->format('d/m/Y')}} + {{ $company->created_at->format('d/m/Y') }}
- - +
+ There are currently no companies. +
{{ $companies->links() }}
-
- diff --git a/resources/views/crew/companies/show.blade.php b/resources/views/crew/companies/show.blade.php index 65393b78..939bc27b 100644 --- a/resources/views/crew/companies/show.blade.php +++ b/resources/views/crew/companies/show.blade.php @@ -38,8 +38,9 @@
- Website: {{ $company->website }} + Website: {{ $company->website }}
Description: {{ $company->description }} @@ -115,17 +116,58 @@
- @forelse($company->users as $user) - {{ $user->name }} | {{ $user->email }} - @if($company->representative->id == $user->id) - (Company representative) - @endif -
- @empty - {{ __('There are currently no users in this company') }} - @endforelse +
    + @forelse($company->users as $user) +
  • + + {{ $user->name }} + + +
    +
    + {{ $user->name }} +
    +
    + {{ $user->email }} +
    + + @if($user->roles->isNotEmpty()) +
    + {{ __('Roles: ') }}{{ optional($user->mainRoles())->join(', ') }} +
    + @endif +
    + + + @if($company->representative->id == $user->id) + + {{ __('Company Representative') }} + + @endif +
  • + @empty +
  • + {{ __('There are currently no users in this company.') }} +
  • + @endforelse +
+ @can('addMember', $company) + + @if ($company->is_approved) + + {{ __('Add Participant') }} + + @else +
+

The company must be approved before adding participants.

+
+ @endif +
+ @endcan @@ -150,24 +192,36 @@ class="mt-1 text-sm leading-6 text-{{ $company->is_approved ? 'green-500' : 'yel @can('approveRequest', $company) @if(!$company->is_approved) -
- @csrf - +
{{ __('Approve') }} - -
- @csrf - - + + {{ __('Reject') }} - -
+ +
@endif @endcan @@ -209,6 +263,45 @@ class="underline" href="{{route('moderator.booths.show', $company->booth)}}">See @endcan + + + Company Presentations + + + + View all presentations related to the company + + + +
+ @forelse($company->presentations as $presentation) + +
+
+ +
+
+

{{ $presentation->name }}

+

Hosted + by: {{ $presentation->speakers_name }}

+
+
+
+ @empty +

The company has no presentations currently.

+ @endforelse +
+
+
+ + + {{ __('Company Sponsorship Status') }} diff --git a/resources/views/crew/editions/index.blade.php b/resources/views/crew/editions/index.blade.php index 28e88157..b2e0dacd 100644 --- a/resources/views/crew/editions/index.blade.php +++ b/resources/views/crew/editions/index.blade.php @@ -15,64 +15,77 @@ - @forelse($editions as $edition) - - -
-
-
- -
-
- {{ $edition->name }} - @if (Edition::current() && Edition::current()->id == $edition->id) -
- ACTIVE -
- @endif -
- - {{ $edition->displayed_state }} - + + + + + + + + + @forelse($editions as $edition) + + + + + @empty + + + + @endforelse + +
+ Edition + + Date +
+
+ +
+
+ {{ $edition->name }} + @if (Edition::current() && Edition::current()->id == $edition->id) +
+ ACTIVE +
+ @endif
+ + {{ $edition->displayed_state }} +
-
-
- -
- @if (!$edition->start_at || !$edition->end_at) - TBD - @else - {{ $edition->start_at->format('d-m-Y H:i') }} - — - {{ $edition->end_at->format('d-m-Y H:i') }} - @endif -
+
+
+ +
+ @if (!$edition->start_at || !$edition->end_at) + TBD + @else + {{ $edition->start_at->format('d-m-Y H:i') }} + — + {{ $edition->end_at->format('d-m-Y H:i') }} + @endif
- - - - @empty -

- There are currently no editions -

- @endforelse +
+ There are currently no editions. +
diff --git a/resources/views/crew/faqs/index.blade.php b/resources/views/crew/faqs/index.blade.php index 978db00f..da0674b5 100644 --- a/resources/views/crew/faqs/index.blade.php +++ b/resources/views/crew/faqs/index.blade.php @@ -13,36 +13,57 @@ @endcan - @forelse($faqs as $index => $faq) - -
-
-
- - - -
- {{$faq->question}} + + + + + + + + + @forelse($faqs as $index => $faq) + + + + + @empty + + + + @endforelse + +
+ Frequently Asked Question + + Created At +
+
+
+
+ + + +
+ {{$faq->question}} +
+
- -
- - {{$faq->created_at->format('d/m/Y')}} -
- - - @empty -

There are currently no FAQs

- @endforelse +
+
+ + {{ $faq->created_at->format('d/m/Y') }} +
+
+ There are currently no FAQs. +
diff --git a/resources/views/crew/presentations/index.blade.php b/resources/views/crew/presentations/index.blade.php index c6fd0eda..ca504df7 100644 --- a/resources/views/crew/presentations/index.blade.php +++ b/resources/views/crew/presentations/index.blade.php @@ -11,47 +11,63 @@ -
-
- - -
-

A big - thank - you to - our - sponsors

-
-
-
-

Gold sponsor

-
- @if(\App\Models\Sponsorship::find(1)) - @foreach(\App\Models\Sponsorship::find(1)->companies as $company) - - @endforeach - @endif -
-
-
-

Silver sponsor

-
- @if(\App\Models\Sponsorship::find(2)) - @foreach(\App\Models\Sponsorship::find(2)->companies as $company) - - @endforeach - @endif -
-
-
-

Bronze sponsor

-
- @if(\App\Models\Sponsorship::find(3)) - @foreach(\App\Models\Sponsorship::find(3)->companies as $company) - - @endforeach - @endif -
+ + @if(!$anySponsorships) +
+
+

+ A big thank you to our sponsors +

+
+
+ @if(\App\Models\Sponsorship::find(1)->companies()->where('is_sponsorship_approved', true)->count() > 0) +
+

Gold sponsor

+
+ @foreach(\App\Models\Sponsorship::find(1)->companies as $company) + @if($company->is_sponsorship_approved) + + @endif + @endforeach +
+
+ @endif + @if(\App\Models\Sponsorship::find(2)->companies()->where('is_sponsorship_approved', true)->count() > 0) +
+

Silver sponsor

+
+ @foreach(\App\Models\Sponsorship::find(2)->companies as $company) + @if($company->is_sponsorship_approved) + + @endif + @endforeach +
+
+ @endif + @if(\App\Models\Sponsorship::find(3)->companies()->where('is_sponsorship_approved', true)->count() > 0) +
+

Bronze sponsor

+
+ @foreach(\App\Models\Sponsorship::find(3)->companies as $company) + @if($company->is_sponsorship_approved) + + @endif + @endforeach +
+
+ @endif
-
+ @endif
diff --git a/routes/web.php b/routes/web.php index 771c0c48..cb4eba12 100644 --- a/routes/web.php +++ b/routes/web.php @@ -60,11 +60,12 @@ Route::get('/faq', [\App\Http\Controllers\FrequentQuestionController::class, 'index'])->name('faq'); Route::view('/contact', 'contact')->name('contact'); -//Route::get('/teams/{team}/requests', [TeamRequestsController::class, 'index'])->name('teams.requests'); -// -//Route::get('/companies/{team}', [TeamsController::class, 'show'])->name('companies.show'); -// -// +// routes for registering from invitation +Route::get('/register/team-invitations/{invitation}', [InvitationController::class, 'show']) + ->middleware(['signed'])->name('registration.page.via.invitation'); +Route::post('/register/team-invitations/{invitation}', [InvitationController::class, 'register']) + ->name('register.via.invitation'); + Route::middleware([ 'auth:sanctum', config('jetstream.auth_session'), @@ -88,12 +89,6 @@ Route::delete('/presentations/{presentation}', [PresentationController::class, 'destroy']) ->name('presentations.destroy'); - // routes for registering from invitation - Route::get('/register/team-invitations/{invitation}', [InvitationController::class, 'show']) - ->middleware(['signed'])->name('registration.page.via.invitation'); - Route::post('/register/team-invitations/{invitation}', [InvitationController::class, 'register']) - ->name('register.via.invitation'); - //route for personal programme Route::get('/my/programme', [ParticipantController::class, 'programme']) ->name('my.programme'); @@ -199,7 +194,7 @@ Route::resource('/moderator/booths', BoothController::class); Route::resource('/moderator/faqs', FrequentQuestionController::class); - Route::post('/moderator/booths/{booth}/approve', [ + Route::post('/moderator/booths/{booth}/approve/{isApproved}', [ App\Http\Controllers\Crew\BoothController::class, 'approve' ])->name('booths.approve'); @@ -207,7 +202,7 @@ '/moderator/companies', App\Http\Controllers\Crew\CompanyController::class ); - Route::post('/moderator/companies/{company}/approve', [ + Route::post('/moderator/companies/{company}/approve/{isApproved}', [ App\Http\Controllers\Crew\CompanyController::class, 'approve' ])->name('companies.approve'); @@ -215,7 +210,7 @@ '/moderator/presentations', App\Http\Controllers\Crew\PresentationController::class ); - Route::post('/moderator/presentations/{presentation}/approve', [ + Route::post('/moderator/presentations/{presentation}/approve/{isApproved}', [ App\Http\Controllers\Crew\PresentationController::class, 'approve' ])->name('presentations.approve'); @@ -230,7 +225,7 @@ ->name('sponsorships.store'); Route::delete('/crew/sponsorships/{company}', [SponsorshipController::class, 'destroy']) ->name('sponsorships.delete'); - Route::post('/crew/sponsorships/{company}/approve', [SponsorshipController::class, 'approve']) + Route::post('/crew/sponsorships/{company}/approve/{isApproved}', [SponsorshipController::class, 'approve']) ->name('sponsorships.approve'); // ====== Crew routes ======== diff --git a/storage/app/config/permissions.yml b/storage/app/config/permissions.yml index eefec429..87917df8 100644 --- a/storage/app/config/permissions.yml +++ b/storage/app/config/permissions.yml @@ -44,6 +44,7 @@ permissions: viewAny: [ event organizer, assistant organizer, company representative, company member, booth owner, pending speaker ] update: company representative delete: company representative + add: event organizer company member invitation: viewAny: company representative create: company representative diff --git a/tailwind.config.js b/tailwind.config.js index a5df93b0..2a84a1c4 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -80,6 +80,19 @@ export default { 'dark:bg-sky-600', 'dark:bg-red-600', 'dark:bg-yellow-600', + 'bg-red-400', + 'hover:bg-red-400', + 'dark:bg-red-800/50', + 'dark:hover:bg-red-800/50', + 'bg-crew-200', + 'hover:bg-crew-200', + 'dark:bg-crew-400/50', + 'dark:hover:bg-crew-400/70', + 'bg-apricot-peach-200', + 'hover:bg-apricot-peach-300', + 'dark:bg-apricot-peach-700/50', + 'dark:hover:bg-apricot-peach-600/75' + ], theme: { extend: { diff --git a/tests/Feature/BoothControllerTest.php b/tests/Feature/BoothControllerTest.php index a08ffe03..a6d09c60 100644 --- a/tests/Feature/BoothControllerTest.php +++ b/tests/Feature/BoothControllerTest.php @@ -81,43 +81,42 @@ public function create_denies_access_to_participant() $response->assertStatus(403); } - /** @test */ - public function store_saves_and_redirects_to_crew() - { - $user = User::factory()->create(); - $user->assignRole('event organizer'); - $company = Company::factory()->create(); - $data = [ - 'company_id' => $company->id, - 'width' => 1, - 'length' => 2, - 'additional_information' => 'Sample info' - ]; - - $response = $this->actingAs($user)->post(route('moderator.booths.store'), $data); - - $response->assertRedirect(route('moderator.booths.index')); - $this->assertDatabaseHas('booths', $data); - } - - /** @test */ - public function store_denies_action_to_participant() - { - $user = User::factory()->create(); - $user->assignRole('participant'); - $company = Company::factory()->create(); - $data = [ - 'company_id' => $company->id, - 'width' => 10, - 'length' => 20, - 'additional_information' => 'Sample info' - ]; - - $response = $this->actingAs($user)->post(route('moderator.booths.store'), $data); - - $response->assertStatus(403); - $this->assertNull($company->booth); - } + // Currently commented out since the route is unused + /* public function store_saves_and_redirects_to_crew() + { + $user = User::factory()->create(); + $user->assignRole('event organizer'); + $company = Company::factory()->create(); + $data = [ + 'company_id' => $company->id, + 'width' => 1, + 'length' => 2, + 'additional_information' => 'Sample info' + ]; + + $response = $this->actingAs($user)->post(route('moderator.booths.store'), $data); + + $response->assertRedirect(route('moderator.booths.index')); + $this->assertDatabaseHas('booths', $data); + } + + public function store_denies_action_to_participant() + { + $user = User::factory()->create(); + $user->assignRole('participant'); + $company = Company::factory()->create(); + $data = [ + 'company_id' => $company->id, + 'width' => 10, + 'length' => 20, + 'additional_information' => 'Sample info' + ]; + + $response = $this->actingAs($user)->post(route('moderator.booths.store'), $data); + + $response->assertStatus(403); + $this->assertNull($company->booth); + }*/ /** @test */ public function show_displays_correct_booth_to_crew() @@ -156,7 +155,7 @@ public function approve_updates_booth_and_redirects_to_crew() }))->create(); $response = $this->actingAs($user) - ->post(route('moderator.booths.approve', [$company->booth, 'approved' => true])); + ->post(route('moderator.booths.approve', [$company->booth, 'isApproved' => true])); $response->assertRedirect(route('moderator.booths.show', ['booth' => $company->booth])); $company->refresh(); @@ -171,7 +170,7 @@ public function approve_denies_action_to_participant() $company = Company::factory()->has(Booth::factory(1))->create(); $response = $this->actingAs($user) - ->post(route('moderator.booths.approve', [$company->booth, 'approved' => true])); + ->post(route('moderator.booths.approve', [$company->booth, 'isApproved' => true])); $response->assertStatus(403); $this->assertEquals(0, $company->booth->is_approved); diff --git a/tests/Feature/CompanyControllerTest.php b/tests/Feature/CompanyControllerTest.php index d0baeec8..844ec067 100644 --- a/tests/Feature/CompanyControllerTest.php +++ b/tests/Feature/CompanyControllerTest.php @@ -208,9 +208,8 @@ public function event_organizer_can_approve_company() $user->assignRole($role); }))->create(); - $response = $this->actingAs($user)->post(route('moderator.companies.approve', $company), [ - 'approved' => true - ]); + $response = $this->actingAs($user) + ->post(route('moderator.companies.approve', ['company' => $company, 'isApproved' => 1])); $response->assertRedirect(route('moderator.companies.show', $company)); $this->assertDatabaseHas('companies', [ @@ -228,9 +227,8 @@ public function event_organizer_can_reject_company() $user->assignRole($role); }))->create(); - $response = $this->actingAs($user)->post(route('moderator.companies.approve', $company), [ - 'approved' => false - ]); + $response = $this->actingAs($user) + ->post(route('moderator.companies.approve', ['company' => $company, 'isApproved' => 0])); $response->assertRedirect(route('moderator.companies.index')); $this->assertDatabaseMissing('companies', ['name' => $company->name]); @@ -244,9 +242,8 @@ public function participant_cannot_approve_or_reject_company() $company->is_approved = false; $company->save(); - $response = $this->actingAs($user)->post(route('moderator.companies.approve', $company), [ - 'approved' => true - ]); + $response = $this->actingAs($user) + ->post(route('moderator.companies.approve', ['company' => $company, 'isApproved' => true])); $response->assertStatus(403); $this->assertEquals(0, $company->is_approved); diff --git a/tests/Feature/PresentationControllerTest.php b/tests/Feature/PresentationControllerTest.php index ca291ff5..a4357ad4 100644 --- a/tests/Feature/PresentationControllerTest.php +++ b/tests/Feature/PresentationControllerTest.php @@ -171,7 +171,7 @@ public function event_organizer_can_approve_presentation() $presentation = Presentation::factory()->create(['is_approved' => false]); $response = $this->actingAs($user) - ->post(route('moderator.presentations.approve', $presentation), ['approved' => true]); + ->post(route('moderator.presentations.approve', ['presentation' => $presentation, 'isApproved' => 1])); $response->assertRedirect(route('moderator.presentations.show', $presentation)); $this->assertDatabaseHas('presentations', ['id' => $presentation->id, 'is_approved' => true]); @@ -184,7 +184,7 @@ public function event_organizer_can_reject_presentation() $presentation = Presentation::factory()->create(['is_approved' => true]); $response = $this->actingAs($user) - ->post(route('moderator.presentations.approve', $presentation), ['approved' => false]); + ->post(route('moderator.presentations.approve', ['presentation' => $presentation, 'isApproved' => 0])); $response->assertRedirect(route('moderator.presentations.index')); $this->assertDatabaseMissing('presentations', ['id' => $presentation->id, 'is_approved' => false]); @@ -199,7 +199,7 @@ public function participant_cannot_approve_or_reject_presentation() $presentation->save(); $response = $this->actingAs($user) - ->post(route('moderator.presentations.approve', $presentation), ['approved' => true]); + ->post(route('moderator.presentations.approve', ['presentation' => $presentation, 'isApproved' => 1])); $response->assertStatus(403); $this->assertDatabaseHas('presentations', ['id' => $presentation->id, 'is_approved' => false]); diff --git a/tests/Feature/SponsorshipControllerTest.php b/tests/Feature/SponsorshipControllerTest.php index 2a4593a9..a3cdbc4b 100644 --- a/tests/Feature/SponsorshipControllerTest.php +++ b/tests/Feature/SponsorshipControllerTest.php @@ -129,7 +129,7 @@ public function event_organizer_can_approve_sponsorship() }))->create(['is_approved' => 1,'sponsorship_id' => 1]); $response = $this->actingAs($user) - ->post(route('moderator.sponsorships.approve', $company), ['approved' => true]); + ->post(route('moderator.sponsorships.approve', ['company' => $company, 'isApproved' => 1])); $response->assertRedirect(route('moderator.sponsorships.show', $company)); $this->assertEquals(1, $company->refresh()->is_sponsorship_approved); @@ -145,7 +145,7 @@ public function event_organizer_can_reject_sponsorship() }))->create(['sponsorship_id' => 1]); $response = $this->actingAs($user) - ->post(route('moderator.sponsorships.approve', $company), ['approved' => false]); + ->post(route('moderator.sponsorships.approve', ['company' => $company, 'isApproved' => 0])); $response->assertRedirect(route('moderator.sponsorships.index')); $this->assertNull($company->refresh()->is_sponsorship_approved); @@ -158,7 +158,7 @@ public function user_cannot_approve_or_reject_sponsorship_without_permission() $company = Company::factory()->create(['sponsorship_id' => 1]); $response = $this->actingAs($user) - ->post(route('moderator.sponsorships.approve', $company), ['approved' => true]); + ->post(route('moderator.sponsorships.approve', ['company' => $company, 'isApproved' => 1])); $response->assertStatus(403); $this->assertDatabaseHas('companies', ['id' => $company->id]);