Laravel 11 Workgroup: Managing Workgroup Meeting Information

Mohamad's interest is in Programming (Mobile, Web, Database and Machine Learning). He is studying at the Center For Artificial Intelligence Technology (CAIT), Universiti Kebangsaan Malaysia (UKM).
Create Migration
Run Artisan command:
php artisan make:migration create_workgroup_meetings_table
Edit the migration file.
(file → database\migrations\yyyy_mm_dd_hhmmss_create_workgroup_meetings_table.php)
<?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()
{
Schema::create('workgroup_meetings', function (Blueprint $table) {
$table->id();
$table->text('name');
$table->text('refn');
$table->text('desn');
$table->text('locn');
$table->integer('estartdate');
$table->integer('attd');
$table->unsignedInteger('workgroup_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down()
{
Schema::dropIfExists('workgroup_meetings');
}
};
Create Workgroup Meetings model.
php artisan make:model WorkgroupMeeting
Edit Workgroup Meeting model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class WorkgroupMeeting extends Model
{
use HasFactory;
protected $fillable = [
'refn',
'desn',
'locn',
'estartdate',
'attd'
];
protected $casts = [
'estartdate' => 'integer',
'attd' => 'integer',
];
}
Run Artisan command to perform migration.
php artisan migrate
[2] Create Web Controller
php artisan make:controller WorkgroupMeetingController --resource
Edit controller script file.
(file → app\Http\Controllers\WorkgroupMeetingController.php)
<?php
namespace App\Http\Controllers;
use App\Models\WorkgroupMeeting;
use Illuminate\Http\Request;
class WorkgroupMeetingController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index($workgroupId)
{
$workgroupMeetings = WorkgroupMeeting::where('workgroup_id', $workgroupId)->get();
return view('workgroup-meetings.index', [
'workgroupId' => $workgroupId,
'workgroupMeetings' => $workgroupMeetings
]);
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
return view('workgroup-meetings.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'name' => 'required',
'refr' => 'required',
'desn' => 'required',
'locn' => 'required',
'estartdate' => 'required|integer',
'attd' => 'required|integer',
'workgroup_id' => 'required|integer',
]);
$workgroupMeeting = WorkgroupMeeting::create($validatedData);
return redirect()->route('workgroup-meetings.index')
->with('success', 'Workgroup meeting created successfully.');
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $workgroupId, string $meetingId)
{
try {
$validatedData = $request->validate([
'refn' => 'required|string',
'desn' => 'required|string',
'locn' => 'required|string',
'estartdate' => 'required|integer',
'attd' => 'required|integer',
]);
// Update the meeting and save it
$meeting = WorkgroupMeeting::findOrFail($meetingId);
$meeting->update($validatedData);
return redirect()->route('workgroup-meetings.index', ['workgroup_id' => $workgroupId])
->with('success', 'Meeting updated successfully.');
} catch (\Illuminate\Validation\ValidationException $e) {
return $e->errors();
return redirect()->back()
->withErrors($e->errors())
->withInput();
}
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}
[3] Create Web View
This step assumes that you have integrated Breeze into your system. Refer to Blade Templates guide for more information about the package.
Edit workgroup-meetings.index:
(file → resources\views\workgroup-meetings\index.blade.php)
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('My Workgroup Meetings') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<div class="mb-2">
<a href="/workgroups" style="color: blue; text-decoration: none;">Workgroups</a> -> Meetings
</div>
@if (session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative" role="alert">
<strong class="font-bold">Success!</strong>
<span class="block sm:inline">{{ session('success') }}</span>
</div>
@endif
<br />
<script>
function toggleButtonNewRecord(elemId) {
var elem = document.getElementById(elemId);
if (elem.classList.contains('hidden')) {
elem.classList.remove('hidden');
} else {
elem.classList.add('hidden');
}
}
function toggleDivNewRecord(elemId) {
var elem = document.getElementById(elemId);
if (elem.classList.contains('hidden')) {
elem.classList.remove('hidden');
} else {
elem.classList.add('hidden');
}
}
</script>
<div id="divNewRecord" class="w-full sm:max-w-md mt-6 px-6 py-4 border bg-white shadow-md overflow-hidden sm:rounded-lg hidden">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('New Meeting') }}
</h2>
<form action="{{ route('workgroups.store') }}" method="POST">
@csrf
<div class="mb-4">
<label for="name" class="block text-gray-700 font-semibold mb-2">Name</label>
<input type="text" id="name" name="name" value="-" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">
</div>
<div class="mb-4">
<label for="refr" class="block text-gray-700 font-semibold mb-2">Reference</label>
<input type="text" id="refr" name="refr" value="-" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">
</div>
<div class="mb-4">
<label for="desc" class="block text-gray-700 font-semibold mb-2">Description</label>
<textarea id="desc" name="desc" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">-</textarea>
</div>
<x-secondary-button type="button" onclick="toggleDivNewRecord('divNewRecord');toggleButtonNewRecord('buttonNewRecord')">
Cancel
</x-danger-button>
<x-primary-button type="submit">
Save
</x-primary-button>
</form>
</div>
<x-tertiary-button id="buttonNewRecord" onclick="toggleDivNewRecord('divNewRecord');toggleButtonNewRecord('buttonNewRecord')">
+ New
</x-tertiary-button>
@if ($workgroupMeetings ->count() > 0)
<div class="mt-4 space-y-4">
@foreach ($workgroupMeetings as $meeting)
<div class="bg-white shadow-md rounded-lg p-4 border border-gray-300 border-solid border-1">
<div class="flex items-center justify-between">
<div>
<h5 class="font-semibold">Keterangan: {{ $meeting->desn ?? '-' }}</h5>
<div class="mb-2">Lokasi: {{ $meeting->locn ?? '-' }}</div>
<div class="mb-2">Tarikh/Masa: {{ date('Y-m-d / g:i A', $meeting->estartdate ?? time()) }}</div>
<p>Kehadiran: {{ $meeting->attd }}</p>
</div>
</div>
<div id="divEditRecord-{{ $meeting->id }}" class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg border hidden">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Edit Meeting') }}
</h2>
<form action="{{ route('workgroup-meetings.update', ['workgroup_id' => $workgroupId, 'id' => $meeting->id]) }}" method="POST" class="edit-meeting">
@csrf
@method('PUT')
<div class="mb-4">
<label for="desn" class="block text-gray-700 font-semibold mb-2">Description</label>
<textarea name="desn" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">{{$meeting->desn ?? '-' }}</textarea>
</div>
<div class="mb-4">
<label for="locn" class="block text-gray-700 font-semibold mb-2">Location</label>
<input type="text" name="locn" value="{{ $meeting->locn ?? '-' }}" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">
</div>
<div class="mb-4">
<label for="estartdate1" class="block text-gray-700 font-semibold mb-2">Start Date</label>
<input type="date" id="estartdate1-{{ $meeting->id }}" name="estartdate1" value="{{ date('Y-m-d', $meeting->estartdate ?? time()) }}" onchange="updateEstartdateField('estartdate-{{ $meeting->id }}','estartdate1-{{ $meeting->id }}')" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">
<input type="hidden" id="estartdate-{{ $meeting->id }}" name="estartdate" value="{{ $meeting->estartdate ?? time() }}">
</div>
<div class="mb-4">
<label for="n" class="block text-gray-700 font-semibold mb-2">Attendance:</label>
<input type="number" name="attd" value="{{ $meeting->attd ?? '-' }}" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">
</div>
<div class="mt-4 flex justify-between">
<x-secondary-button type="button" onclick="toggleDivEditRecord('divEditRecord-{{ $meeting->id }}');
toggleButtonEditRecord('buttonEditRecord-{{ $meeting->id }}');">
Cancel
</x-danger-button>
<x-primary-button type="submit" class="bg-blue-500 hover:bg-blue-700 text-black font-bold py-2 px-4 rounded">
Save
</x-primary-button>
</div>
</form>
</div>
<div class="mt-4 text-left">
<x-tertiary-button href="#" id="buttonEditRecord-{{ $meeting->id }}" onclick="toggleDivEditRecord('divEditRecord-{{ $meeting->id }}');
toggleButtonEditRecord('buttonEditRecord-{{ $meeting->id }}');">
View/Edit
</x-tertiary-button>
<a href="meetings/{{ $meeting->id }}/agendas" class="inline-flex items-center px-4 py-2 bg-gray-500 border border-gray-300 rounded-md font-semibold text-xs text-white uppercase tracking-widest shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 transition ease-in-out duration-150">
Browse
</a>
</div>
</div>
@endforeach
</div>
@else
<p class="mt-4 text-gray-600">You haven't created any workgroup meetings yet.</p>
@endif
<script>
function toggleButtonEditRecord(elemId) {
var elem = document.getElementById(elemId);
if (elem.classList.contains('hidden')) {
elem.classList.remove('hidden');
} else {
elem.classList.add('hidden');
}
}
function toggleDivEditRecord(elemId) {
var elem = document.getElementById(elemId);
if (elem.classList.contains('hidden')) {
elem.classList.remove('hidden');
} else {
elem.classList.add('hidden');
}
}
function updateEstartdateField(elemId, elemId1) {
var estartdate1Input = document.getElementById(elemId1);
var estartdateInput = document.getElementById(elemId);
var edate = Math.floor(new Date(estartdate1Input.value).getTime() / 1000);
console.log(edate);
estartdateInput.value = (edate);
}
</script>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>
[4] Update Web Route
(file → routes\web.php)
use App\Http\Controllers\WorkgroupMeetingController;
Route::middleware('auth')->group(function () {
Route::group(['prefix' => 'workgroups'], function () {
Route::get('{workgroup_id}/meetings', [WorkgroupMeetingController::class, 'index'])
->name('workgroup-meetings.index');
Route::get('{workgroup_id}/meetings/create', [WorkgroupMeetingController::class, 'create'])
->name('workgroup-meetings.create');
Route::post('{workgroup_id}/meetings', [WorkgroupMeetingController::class, 'store'])
->name('workgroup-meetings.store');
Route::get('{workgroup_id}/meetings/{id}/edit', [WorkgroupMeetingController::class, 'edit'])
->name('workgroup-meetings.edit');
Route::put('{workgroup_id}/meetings/{id}', [WorkgroupMeetingController::class, 'update'])
->name('workgroup-meetings.update');
Route::delete('{workgroup_id}/meetings/{id}', [WorkgroupMeetingController::class, 'destroy'])
->name('workgroup-meetings.destroy');
});
});
[5] Test
Click New Meeting button.