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.