Laravel 11 Workgroup: Managing Workgroup Meeting Information

Laravel 11 Workgroup: Managing Workgroup Meeting Information

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.