phayes0289's avatar

Need Help Displaying Signups.

The following is my Laravel index method for an overtime sign-up module I am making. I am looking for a better way to display overtime signups for up to sixty people, each one having up to six overtime signups. I am trying to avoid putting PHP onto the blade page.

public function index(Request $request)
    {
        // Check if 'shiftdate' is not in the request and set default value
        if (!$request->has('shiftdate')) {
            $request['shiftdate'] = Carbon::now()->format('Y-m-d');
        }

        $shiftdate = $request['shiftdate'];

        $submittedDate = Carbon::createFromFormat('Y-m-d', $request->input('shiftdate'));
        $date = $submittedDate->format('m/d/Y');

        $shiftID = ShiftHelper::getShift($date, '1/1/2023', '1,2,3,4');

        $users = User::whereHas('CurrentAssignment', function ($query) use ($shiftID) {
            $query->where('shift_id', $shiftID);
        })->with('CurrentAssignment')
            ->where('personnel', 1)
            ->where('separation_reason', null)
            ->get()
            ->groupBy(function ($user) {
                return $user->CurrentAssignment->station_id;
            })
            ->sortKeys();

        // Increment the shift date by one day
        $nextDay = Carbon::createFromFormat('Y-m-d', $shiftdate)->addDay()->format('Y-m-d');

        // Eloquent query to get the next six start_dt values greater than the next day after the given shiftDate
        $dates = OvertimeShifts::where('start_dt', '>', $nextDay)
            ->orderBy('start_dt', 'ASC')
            ->limit(6)
            ->get(); // Use get() instead of pluck()

        return view('stamfordct::overtime/signup/index', compact('users', 'shiftdate', 'dates'));
    }

It basically produces a list of all users in a certain shift grouped by Fire Station. It currently shows a default “unchecked” image ( "/media/images/checkboxes/unchecked_box.png") for each overtime signup period.

There is a variable for each called “shiftdate” that defines what info should be displayed on the blade page. For any given shiftdate, the blade output will display a total of six possible overtime signup periods over three days, beginning with the very next day of the “shiftdate”. For each of those three days, there are two possible periods to signup for. One is from “08:00:00” until “18:00:00”. The other is “18:00:00” until “08:00:00 the next day. This will output six columns of possible sign-up periods. This is what the blade output of those six shifts currently looks like:

foreach ($users as $station_id => $usersInStation)
                <div class="row bg-fusion-50">
                    <div class="col-12 text-center mt-2">
                        <h2>Station: {{ $station_id }}</h2>
                    </div>
                </div>

                @foreach ($usersInStation as $index => $user)
                    <div class="row mt-1 mb-1 {{ $index % 2 == 0 ? 'bg-primary-50' : 'bg-white' }}">
                        <div class="col-1 pt-2">{{ $user->empid }}</div>
                        <div class="col-5 pt-2">{{ $user->CurrentAssignment->rank->code }} {{ $user->lastname }}
                            , {{ $user->firstname }}</div>
                        @foreach ($dates as $date)
                            <div class="col-1">
                                <div class="d-flex justify-content-center align-items-center p-1 m-1">
                                    <img src="/media/images/checkboxes/unchecked_box.png" alt=""
                                         style="width:20px;">
                                    <i class="fal fa-edit ml-2 mr-1"></i>
                                    <i class="fal fa-trash ml-2 mr-1"></i>
                                </div>

                            </div>

                        @endforeach
                    </div>
                @endforeach
            @endforeach

Each user can sign up for any of those six shifts over a three-day period, as defined by the index method above. When a user signs up to work overtime on a given day and overtime period, a single record is created and recorded for each period in a table named "overtime_signups. This table migration looks like this:

Schema::create('overtime_signups', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
            $table->foreignId('station_id')->nullable()->constrained('stations')->onDelete('set null');
            $table->foreignId('rank_id')->nullable()->constrained('ranks')->onDelete('set null');
            $table->foreignId('shift_id')->nullable()->constrained('shifts')->onDelete('set null');
            $table->foreignId('division_id')->nullable()->constrained('divisions')->onDelete('set null');
            $table->decimal('seniority_number', 8, 2);
            $table->dateTimeTz('shift_date');
            $table->dateTimeTz('start_dt');
            $table->dateTimeTz('end_dt');
            $table->integer('duration');
            $table->longText('notes')->nullable();
            $table->ipAddress('ip_address');
            $table->foreignId('created_by')->nullable()->constrained('users')->onDelete('set null');
            $table->foreignId('updated_by')->nullable()->constrained('users')->onDelete('set null');
            $table->timestamps();
        });

The "start_dt" defines either the 08:00:00 or the 18:00:00 start time for one of the two daily overtime periods. "end_dt" defines the end time for either of those two same shifts.

I need to help developing the eloquent query that is needed to return the signups for all the users displayed and match any of the six given overtime periods as defined by $dates in the index method.

I also need help with the code on the blade page. I need to modify it to replaced the default “unchecked” image with the “checked” image if there is a matching signup record for any given shiftDate and start_dt.

I am open to writing any code currently in the index method above. I just need to display the sign-ups for each user using the given format of six columns, one for each overtime sugnup period.

0 likes
3 replies
LaryAI's avatar
Level 58

To achieve the desired functionality, you need to modify both the controller and the Blade template. Here's a step-by-step solution:

Step 1: Modify the Controller

First, you need to fetch the overtime signups for the users and the specified dates. You can do this by modifying the index method to include the necessary Eloquent query.

public function index(Request $request)
{
    // Check if 'shiftdate' is not in the request and set default value
    if (!$request->has('shiftdate')) {
        $request['shiftdate'] = Carbon::now()->format('Y-m-d');
    }

    $shiftdate = $request['shiftdate'];

    $submittedDate = Carbon::createFromFormat('Y-m-d', $request->input('shiftdate'));
    $date = $submittedDate->format('m/d/Y');

    $shiftID = ShiftHelper::getShift($date, '1/1/2023', '1,2,3,4');

    $users = User::whereHas('CurrentAssignment', function ($query) use ($shiftID) {
        $query->where('shift_id', $shiftID);
    })->with('CurrentAssignment')
        ->where('personnel', 1)
        ->where('separation_reason', null)
        ->get()
        ->groupBy(function ($user) {
            return $user->CurrentAssignment->station_id;
        })
        ->sortKeys();

    // Increment the shift date by one day
    $nextDay = Carbon::createFromFormat('Y-m-d', $shiftdate)->addDay()->format('Y-m-d');

    // Eloquent query to get the next six start_dt values greater than the next day after the given shiftDate
    $dates = OvertimeShifts::where('start_dt', '>', $nextDay)
        ->orderBy('start_dt', 'ASC')
        ->limit(6)
        ->get(); // Use get() instead of pluck()

    // Fetch overtime signups for the users and dates
    $signups = OvertimeSignup::whereIn('user_id', $users->flatten()->pluck('id'))
        ->whereIn('start_dt', $dates->pluck('start_dt'))
        ->get()
        ->groupBy('user_id');

    return view('stamfordct::overtime/signup/index', compact('users', 'shiftdate', 'dates', 'signups'));
}

Step 2: Modify the Blade Template

Next, you need to update the Blade template to check if a user has signed up for a specific overtime period and display the appropriate image.

@foreach ($users as $station_id => $usersInStation)
    <div class="row bg-fusion-50">
        <div class="col-12 text-center mt-2">
            <h2>Station: {{ $station_id }}</h2>
        </div>
    </div>

    @foreach ($usersInStation as $index => $user)
        <div class="row mt-1 mb-1 {{ $index % 2 == 0 ? 'bg-primary-50' : 'bg-white' }}">
            <div class="col-1 pt-2">{{ $user->empid }}</div>
            <div class="col-5 pt-2">{{ $user->CurrentAssignment->rank->code }} {{ $user->lastname }}, {{ $user->firstname }}</div>
            @foreach ($dates as $date)
                <div class="col-1">
                    <div class="d-flex justify-content-center align-items-center p-1 m-1">
                        @php
                            $signup = $signups[$user->id]->firstWhere('start_dt', $date->start_dt) ?? null;
                        @endphp
                        <img src="{{ $signup ? '/media/images/checkboxes/checked_box.png' : '/media/images/checkboxes/unchecked_box.png' }}" alt=""
                             style="width:20px;">
                        <i class="fal fa-edit ml-2 mr-1"></i>
                        <i class="fal fa-trash ml-2 mr-1"></i>
                    </div>
                </div>
            @endforeach
        </div>
    @endforeach
@endforeach

Explanation

  1. Controller Modifications:

    • Added a query to fetch overtime signups for the users and the specified dates.
    • Grouped the signups by user_id for easier access in the Blade template.
  2. Blade Template Modifications:

    • Used a @php directive to check if a user has signed up for a specific overtime period.
    • Displayed the appropriate image based on whether a signup record exists.

This solution ensures that the Blade template remains clean and the logic is handled in the controller, adhering to the separation of concerns principle.

JussiMannisto's avatar

You don't need to do this:

// Check if 'shiftdate' is not in the request and set default value
if (!$request->has('shiftdate')) {
	$request['shiftdate'] = Carbon::now()->format('Y-m-d');
}

$shiftdate = $request['shiftdate'];

You can simply pass a default value as the second parameter of $request->input():

$shiftdate = $request->input('shiftdate', Carbon::now()->format('Y-m-d'));

Ps. You don't have to use Lary to generate code. You can use ChatGPT. Let's use this forum for actual questions.

martinbean's avatar

@JussiMannisto Laravel also has a date method on the Request object to get well-formed date instances:

$shiftDate = $request->date('shift_date', Date::now());
1 like

Please or to participate in this conversation.