Laravel 11 Workgroup: Creating Collaborative Environments (Linked By Email)

Laravel 11 Workgroup: Creating Collaborative Environments (Linked By Email)

that caters for different project requirements, communication styles, and workflow preferences.

[0] Create Laravel project with Auth API

Follow the previous article, or download a quick start project.

[1] Create migration

Run Artisan command:

php artisan make:migration create_workgroups_table

Edit the migration file.

(file → database\migrations\yyyy_mm_dd_hhmmss_create_workgroups_table.php)

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateWorkgroupsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('workgroups', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('refr');
            $table->text('desc');
            $table->string('locn');
            $table->integer('estartdate');
            $table->string('key1');
            $table->string('key2');
            $table->string('key3');
            $table->string('key4');
            $table->string('key5');
            $table->integer('n');
            $table->integer('admn');
            $table->integer('cord');
            $table->integer('oper');
            $table->integer('mngr');
            $table->string('mngr_email');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('workgroups');
    }
}

Create Workgroup model.

php artisan make:model Workgroup

Edit Workgroup model.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Workgroup extends Model
{
    use HasFactory;
    protected $fillable = [
        'name',
        'refr',
        'desc',
        'locn',
        'estartdate',
        'key1',
        'key2',
        'key3',
        'key4',
        'key5',
        'n',
        'admn',
        'cord',
        'oper',
        'mngr',
        'mngr_email',
    ];  
}

Run Artisan command to perform migration.

php artisan migrate

[2] Create Web Controller

Create controller script file

php artisan make:controller WorkgroupsController

Edit controller script file.

(file → app\Http\Controllers\WorkgroupsController.php)

<?php

namespace App\Http\Controllers;

use App\Models\Workgroup;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class WorkgroupsController extends Controller
{
    public function index()
    {
        $user = Auth::user();
        $workgroups = Workgroup::where('mngr_email', $user->email)
                               ->get();

        return view('workgroups.index', [
            'workgroups' => $workgroups,
        ]);
    }

    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'name' => 'required|string|max:255',
            'refr' => 'required|string',
            'desc' => 'required|string',
            'locn' => 'required|string',
            'estartdate' => 'required|integer',
            'key1' => 'required|string',
            'key2' => 'required|string',
            'key3' => 'required|string',
            'key4' => 'required|string',
            'key5' => 'required|string',
            'n' => 'required|integer',
        ]);

        $user = Auth::user();

        $workgroup = Workgroup::create([
            'mngr_email' => $user->email,
            'name' => $validatedData['name'],
            'refr' => $validatedData['refr'],
            'desc' => $validatedData['desc'],
            'locn' => $validatedData['locn'],
            'estartdate' => $validatedData['estartdate'],
            'key1' => $validatedData['key1'],
            'key2' => $validatedData['key2'],
            'key3' => $validatedData['key3'],
            'key4' => $validatedData['key4'],
            'key5' => $validatedData['key5'],
            'admn' => 0,
            'cord' => 0,
            'oper' => 0,
            'mngr' => $user->id,
            'n' => $validatedData['n'],
        ]);

        return redirect()->route('workgroups.index')
            ->with('success', 'Workgroup created successfully.');
    }
}

[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 workgroups.index:

(file → resources\views\workgroups\index.blade.php)

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Your Workgroups') }}
        </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">

                    <script>
                        document.addEventListener('DOMContentLoaded', function() {
                            const buttonShowFormNewWorkgroup = document.getElementById('buttonShowFormNewWorkgroup');
                            const formNewWorkgroup = document.getElementById('newWorkgroupForm1');
                            const buttonCancelFormNewWorkgroup = document.getElementById('buttonCancelFormNewWorkgroup');

                            buttonShowFormNewWorkgroup.addEventListener('click', function() {
                                formNewWorkgroup.classList.toggle('hidden');
                                buttonShowFormNewWorkgroup.classList.add('hidden');
                            });

                            buttonCancelFormNewWorkgroup.addEventListener('click', function() {
                                formNewWorkgroup.classList.toggle('hidden');
                                buttonShowFormNewWorkgroup.classList.remove('hidden');
                            });

                        });
                    </script>

                    @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/>

                    <x-primary-button id="buttonShowFormNewWorkgroup">
                        New Workgroup
                    </x-primary-button>


                    <div id="newWorkgroupForm1" class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg hidden">
                    <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                        {{ __('New Workgroup') }}
                    </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>
                        <div class="mb-4">
                            <label for="locn" class="block text-gray-700 font-semibold mb-2">Location</label>
                            <input type="text" id="locn" name="locn" 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="estartdate" class="block text-gray-700 font-semibold mb-2">Start Date</label>
                            <input type="number" id="estartdate" value="0" name="estartdate" 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="key1" class="block text-gray-700 font-semibold mb-2">Key 1</label>
                            <input type="text" id="key1" name="key1" 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="key2" class="block text-gray-700 font-semibold mb-2">Key 2</label>
                            <input type="text" id="key2" name="key2" 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="key3" class="block text-gray-700 font-semibold mb-2">Key 3</label>
                            <input type="text" id="key3" name="key3" 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="key4" class="block text-gray-700 font-semibold mb-2">Key 4</label>
                            <input type="text" id="key4" name="key4" 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="key5" class="block text-gray-700 font-semibold mb-2">Key 5</label>
                            <input type="text" id="key5" name="key5" 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="n" class="block text-gray-700 font-semibold mb-2">N</label>
                            <input type="number" id="n" name="n" value="0" class="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring focus:border-blue-300">
                        </div>

                        <x-secondary-button id="buttonCancelFormNewWorkgroup">
                            Cancel
                        </x-secondary-button>

                        <x-primary-button id="buttonSaveFormNewWorkgroup" type="submit">
                            Save Workgroup
                        </x-primary-button>

                    </form>
                </div>

                @if ($workgroups->count() > 0)
                <div class="mt-4 space-y-4">
                    @foreach ($workgroups as $workgroup)
                    <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">{{ $workgroup->name }}</h5>
                                <p class="text-gray-600">{{ $workgroup->desc }}</p>
                                <p class="text-gray-600">Reference: {{ $workgroup->refr }}</p>
                                <p class="text-gray-600">Location: {{ $workgroup->locn }}</p>
                                <p class="text-gray-600">Start Date: {{ $workgroup->estartdate }}</p>
                                <p class="text-gray-600">Key 1: {{ $workgroup->key1 }}</p>
                                <p class="text-gray-600">Key 2: {{ $workgroup->key2 }}</p>
                                <p class="text-gray-600">Key 3: {{ $workgroup->key3 }}</p>
                                <p class="text-gray-600">Key 4: {{ $workgroup->key4 }}</p>
                                <p class="text-gray-600">Key 5: {{ $workgroup->key5 }}</p>
                                <p class="text-gray-600">N: {{ $workgroup->n }}</p>
                            </div>
                            <div class="space-x-2">
                                <a href="#" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
                                    Edit
                                </a>
                                <a href="#" class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">
                                    Delete
                                </a>
                            </div>
                        </div>
                    </div>
                    @endforeach
                </div>
                @else
                <p class="mt-4 text-gray-600">You haven't created any workgroups yet.</p>
                @endif

                </div>
            </div>
        </div>
    </div>


</x-app-layout>

Add the navigation link for the workgroups page in the navigation layout file:

(file →resources\views\layouts\navigation.blade.php)

                <!-- Navigation Links -->
                <div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
                    <x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
                        {{ __('Dashboard') }}
                    </x-nav-link>
                    <x-nav-link :href="route('workgroups.index')" :active="request()->routeIs('workgroups.*')">
                        {{ __('Workgroups') }}
                    </x-nav-link>
                </div>

[4] Update Web Route

...
use App\Http\Controllers\WorkgroupsController;
Route::get('/workgroups', [WorkgroupsController::class, 'index'])->name('workgroups.index');
Route::get('/workgroups/create', [WorkgroupsController::class, 'create'])->name('workgroups.create');
Route::post('/workgroups', [WorkgroupsController::class, 'store'])->name('workgroups.store');
...

[5] Test

Click New Workgroup button.

Enter details of the Workgroup e.g.:

  • Name = Group1

  • Description=This is Group1

Click Save Workgroup button.

Outcome:

Download:

https://archive.org/download/laravelprojects/lara11breeze_userapi_workgroups_20240409.zip

Further reading:

If you want to implement belongs_to and has_many relationship, refer https://hashnotes.hashnode.dev/laravel-11-workgroup-creating-collaborative-environments