mad-resource-timeline
Timeline de recursos.
Modo resource timeline do <mad-calendar> — grade com horas no eixo
vertical e (dia × recurso) no eixo horizontal. Ativado declarando um sub-tag
<mad-calendar-resource> com a fonte dos recursos (linhas), ou um
loadResources() customizado, numa subclasse de MadCalendarComponent. Bom
para agenda de salas, equipamentos, escala de funcionários, alocação de
quartos de hotel, etc. Não é uma tag isolada — é sempre <mad-calendar>
configurado nesse modo.
Importante: essa grade é renderizada por um componente Alpine próprio do framework (
madResourceTimeline, view internacomponents.resource-timeline), não pelo pluginresourceTimelinereal do FullCalendar. Opções de pass-through específicas do FullCalendar (ex:resourceAreaWidth) não têm efeito aqui — ver Gotchas.
Quick start
<mad-calendar
calendar-id="cal-salas"
model="Reserva" database="minierp"
title-field="finalidade"
start-field="dt_inicio" end-field="dt_fim"
default-view="resourceTimelineDay"
time-range="08:00-18:00"
slot-duration="01:00"
slot-click-target="ReservaForm::onCreate({date},{resourceId})">
<mad-calendar-resource
model="Sala"
title-field="nome"
color-field="cor"
label="Sala" />
</mad-calendar>
Os eventos carregam automaticamente a partir de model + start-field +
end-field (o próprio componente fabrica o endpoint estático getEvents()
internamente). Não declare events-url manualmente — é só um escape hatch
para apontar pra um endpoint externo custom; o valor default já funciona.
Atributos do <mad-calendar-resource>
| Attr | Descrição |
|---|---|
model |
Classe do model Eloquent do recurso |
database |
Conexão (default MAIN_DATABASE) |
id-field |
Default id |
title-field |
Coluna do nome do recurso (default name) |
color-field |
Coluna com hex color |
label |
Label visível no header da coluna de recursos (default Recurso) |
order-by |
Ordenação dos recursos |
Filtros do repo de recursos
Use <mad-calendar-resource-filter> para filtrar quais recursos aparecem (mesmo
shape field/op/value do <mad-calendar-filter> que filtra eventos):
<mad-calendar default-view="resourceTimelineDay">
<mad-calendar-resource model="Sala" title-field="nome" />
<mad-calendar-resource-filter field="ativo" op="=" value="1" />
<mad-calendar-resource-filter field="unidade_id" op="=" :value="$unidadeId" />
</mad-calendar>
Quantos dias aparecem na grade
A grade sempre mostra slots de hora no eixo vertical (time-range +
slot-duration); o que muda entre as views é só o número de colunas de dia no
eixo horizontal:
default-view |
Dias exibidos |
|---|---|
resourceTimelineDay (ou day) |
1 dia |
qualquer outro valor (resourceTimelineWeek, resourceTimelineMonth, ...) |
N dias (default 4) |
Ajuste N explicitamente com num-days:
<mad-calendar default-view="resourceTimelineWeek" num-days="7" time-range="08:00-18:00">
<mad-calendar-resource model="Sala" title-field="nome" />
</mad-calendar>
O usuário também navega pela toolbar embutida (◀ ▶ Hoje, "Dia" / "N dias").
Slot click — criar evento em célula vazia
<mad-calendar
slot-click-target="ReservaForm::onCreate({date},{resourceId})">
<mad-calendar-resource model="Sala" title-field="nome" />
</mad-calendar>
Placeholders disponíveis:
{date}— Y-m-d H:i:s do slot clicado{resourceId}— ID do recurso (linha) clicado{resourceTitle}— título do recurso clicado
Hook PHP custom
class AgendaSalas extends MadCalendarComponent
{
public function onSlotClick(string $date, string $resourceId, string $resourceTitle): MadResponse
{
// Lógica custom — ex: validar disponibilidade antes de abrir form
if (!$this->disponivel($date, $resourceId)) {
return MadToast::warning("Sala ocupada");
}
return MadResponse::open('ReservaForm', [
'date' => $date,
'sala_id' => $resourceId,
]);
}
// Recursos hardcoded (sem query ao banco)
protected function loadResources(): array
{
return [
['id' => '1', 'title' => 'Sala A', 'color' => '#3b82f6'],
['id' => '2', 'title' => 'Sala B', 'color' => '#f59e0b'],
];
}
}
Exemplo end-to-end — agenda de salas
<?php
use Mad\Calendar\MadCalendarComponent;
use Mad\Http\MadResponse;
class AgendaSalas extends MadCalendarComponent
{
protected static string $wrapper = self::INTERNAL;
public function onSlotClick(string $date, string $resourceId, string $resourceTitle): MadResponse
{
return MadResponse::open('ReservaForm', [
'date' => $date,
'sala_id' => $resourceId,
]);
}
protected function view(): string|array
{
return 'agenda.agenda-salas';
}
}
<mad-page-container>
<mad-page-header title="Agenda de Salas" icon="calendar" />
<mad-page-content>
<mad-calendar
calendar-id="cal-salas"
model="ReservaSala" database="minierp"
title-field="finalidade"
start-field="dt_inicio" end-field="dt_fim"
color-field="cor"
default-view="resourceTimelineDay"
time-range="08:00-18:00"
slot-duration="01:00"
editable auto-update
click-target="ReservaForm::onEdit({id})">
<mad-calendar-resource
model="Sala"
title-field="nome"
color-field="cor"
label="Sala" />
<mad-calendar-resource-filter field="ativo" op="=" value="1" />
<mad-calendar-filter field="cancelada" op="=" value="0" />
</mad-calendar>
</mad-page-content>
</mad-page-container>
Gotchas
- Modo resource ativa sozinho — basta declarar
<mad-calendar-resource>(ou sobrescreverloadResources()retornando linhas).default-viewcomeçando comresourceTimelinenão é obrigatório pra ativar o modo — ele só decide se a grade mostra 1 dia ou N dias (ver seção acima) - Recursos vazios = cai pro
<mad-calendar>normal, não fica vazio — seloadResources()retornar[], o componente faz fallback silencioso pra view padrão (full-calendar, sem a grade de recursos) em vez de renderizar uma timeline vazia loadResources()sobrescrito substitui<mad-calendar-resource>por completo — se a subclasse override o método, ele vale sozinho; declare apenas uma das duas fontes- Slot click usa
slot-click-target, nãoday-click-target— placeholders diferentes ({resourceId}/{resourceTitle}vs só{date}) - Não é o FullCalendar real — a grade é um componente Alpine próprio do
framework; opções de pass-through tipo
extra-options='{"resourceAreaWidth": 200}'(que fariam sentido no plugin real do FullCalendar) não têm efeito aqui. A única chave deextra-optionslida nesse modo énumDays(alternativa ao atributonum-days)