MAD Lab
/
Tutor > Módulos visuais > Calendário de recursos

Calendário de recursos

Módulos visuais

mad-calendar-resource mad-resource-timeline
Agenda de salas (resource timeline)

mad-calendar com mad-calendar-resource — cada linha é um recurso (sala) e os eventos ficam alinhados na coluna do horário. É o mesmo componente do calendário comum; o resource-timeline entra sozinho quando um recurso é configurado.

Cada linha é uma sala — passe o mouse num evento pra ver o popover.
resources/views/tutor/examples/modulos-calendario-recursos/timeline.blade.php
@php($that = \Mad\Component\MadRenderContext::getComponent())

<mad-calendar
    calendar-id="tutor-modulos-calendario-recursos"
    model="TutorEventoRecursoEvento" database="business"
    title-field="titulo" start-field="inicio" end-field="fim" color-field="cor"
    resource-field="recurso_id">

    <mad-calendar-toolbar>
        <span style="font-size:12px; color:var(--mad-text-muted);">
            Cada linha é uma sala — passe o mouse num evento pra ver o popover.
        </span>
    </mad-calendar-toolbar>

    <mad-calendar-resource model="TutorEventoRecurso" database="business"
        id-field="id" title-field="nome" color-field="cor" label="Sala" order-by="nome" />
</mad-calendar>
Código-fonte completo da página
app/control/Tutor/TutorModulosCalendarioRecursos.php
<?php

namespace App\Control\Tutor;

use App\Models\TutorDemo\TutorEventoRecurso;
use App\Support\Tutor\TutorCatalog;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Mad\Calendar\MadCalendarComponent;
use Mad\Http\MadResponse;

/**
 * TutorModulosCalendarioRecursos — página "Calendário de recursos" do MAD
 * Tutor (LOTE L9 / Onda 1).
 *
 * Estende Mad\Calendar\MadCalendarComponent — a view "Resource Timeline" é o
 * MESMO `<mad-calendar>`, só que com `<mad-calendar-resource>` configurado
 * (aí o MadFullCalendar interno troca sozinho pra
 * components.resource-timeline — ver MadCalendarComponent::renderCalendarHtml,
 * `$wantResource = $this->resourceModel !== '' || ...`). Não existe uma tag
 * `<mad-resource-timeline>` separada no compiler; "mad-resource-timeline" no
 * catálogo é o nome conceitual dessa VIEW, não uma tag literal — ver
 * relatório do lote.
 *
 * Mesma regra de instância única do TutorModulosCalendario (config em sessão
 * chaveada só pela classe) — 1 `<mad-calendar>` só nesta página.
 */
class TutorModulosCalendarioRecursos extends MadCalendarComponent
{
    protected static string $wrapper = self::INTERNAL;

    protected string $catalogKey = 'modulos_calendario_recursos';

    public function mount(array $params = []): void
    {
        $this->ensureFixture();
        parent::mount($params);
    }

    protected function view(): string|array
    {
        return TutorCatalog::page($this->catalogKey)['view'];
    }

    public function onEventClick(string $id, string $title, string $view): MadResponse
    {
        return (new MadResponse())->toast("Reserva: {$title}", 'info');
    }

    // ── Fixture (molde: KanbanDevView::ensureFixture) ───────────────────────

    private function ensureFixture(): void
    {
        $schema = Schema::connection('business');

        if (!$schema->hasTable('tutor_evento_recursos')) {
            $schema->create('tutor_evento_recursos', function ($t) {
                $t->increments('id');
                $t->string('nome');
                $t->string('cor', 16)->nullable();
            });
        }
        if (!$schema->hasTable('tutor_evento_recurso_eventos')) {
            $schema->create('tutor_evento_recurso_eventos', function ($t) {
                $t->increments('id');
                $t->string('titulo');
                $t->unsignedInteger('recurso_id');
                $t->dateTime('inicio');
                $t->dateTime('fim');
                $t->string('cor', 16)->nullable();
            });
        }

        if (TutorEventoRecurso::query()->count() > 0) {
            return;
        }

        $salas = [
            ['id' => 1, 'nome' => 'Sala A — Térreo',  'cor' => '#3b82f6'],
            ['id' => 2, 'nome' => 'Sala B — 2º andar', 'cor' => '#f59e0b'],
            ['id' => 3, 'nome' => 'Sala C — Auditório', 'cor' => '#8b5cf6'],
        ];
        DB::connection('business')->table('tutor_evento_recursos')->insert($salas);

        $titulos = ['Reunião de time', 'Apresentação ao cliente', 'Entrevista', 'Workshop', 'Alinhamento'];
        $hoje    = new \DateTimeImmutable('today');
        $rows    = [];

        foreach ($salas as $i => $sala) {
            for ($d = 0; $d <= 4; $d++) {
                if ($d % (2 + $i) === 0) {
                    continue; // agenda esburacada de propósito (nem toda sala ocupada todo dia)
                }
                $dia     = $hoje->modify("{$d} days");
                $horaIni = 9 + $i * 2;
                $inicio  = $dia->setTime($horaIni, 0);
                $fim     = $inicio->modify('+60 minutes');

                $rows[] = [
                    'titulo'     => $titulos[($i + $d) % count($titulos)],
                    'recurso_id' => $sala['id'],
                    'inicio'     => $inicio->format('Y-m-d H:i:s'),
                    'fim'        => $fim->format('Y-m-d H:i:s'),
                    'cor'        => $sala['cor'],
                ];
            }
        }

        DB::connection('business')->table('tutor_evento_recurso_eventos')->insert($rows);
    }
}
resources/views/tutor/modulos/calendario-recursos.blade.php
<x-tutor-page page="modulos_calendario_recursos">
    <x-tutor-demo demo="tutor.examples.modulos-calendario-recursos.timeline"
        title="Agenda de salas (resource timeline)" desc="mad-calendar com mad-calendar-resource — cada linha é um recurso (sala) e os eventos ficam alinhados na coluna do horário. É o mesmo componente do calendário comum; o resource-timeline entra sozinho quando um recurso é configurado." />
</x-tutor-page>