@props([
/** "investor" or "startup" — selects the schema source + endpoint shape. */
'entity',
/** Section key (e.g. "identity") — must exist in EntitySectionSchema. */
'sectionKey',
/** PATCH endpoint that accepts {fields:{...}}. Required. */
'updateUrl',
/** The Eloquent model instance whose data this section displays. Required. */
'model',
/** Section title (already translated string) for the card header. */
'title',
/** Optional icon name (without the `#icon-` prefix). */
'icon' => 'shield',
/** Optional icon background colour pair: ['bg' => '...', 'fg' => '...']. */
'iconStyle' => null,
/** sessionStorage collapse key (e.g. "inv.identity"). Required for persistence. */
'collapseKey',
/** Whether the card starts open. Defaults to true. */
'open' => true,
])
@php
use App\Services\Admin\EntitySectionSchema;
$schema = EntitySectionSchema::getSection($entity, $sectionKey);
$fields = $schema['fields'] ?? [];
// Snapshot current field values from the model. The snapshot is sent
// to the Alpine component so Cancel can revert + Save can diff.
// Multiselect fields read their pivot column off the relation's items;
// dates serialise to YYYY-MM-DD so binds cleanly.
$currentValues = [];
foreach ($fields as $name => $def) {
if (($def['type'] ?? null) === 'multiselect') {
$relation = $def['relation'];
$column = $def['pivot_column'];
$items = $model->relationLoaded($relation)
? $model->{$relation}
: $model->{$relation}()->get();
$currentValues[$name] = $items->pluck($column)->map(fn ($id) => (int) $id)->filter()->values()->all();
continue;
}
if (($def['type'] ?? null) === 'string_list') {
$raw = $model->getAttribute($name);
$currentValues[$name] = is_array($raw)
? array_values(array_filter(array_map('strval', $raw), fn ($v) => trim($v) !== ''))
: [];
continue;
}
$raw = $model->getAttribute($name);
if (($def['type'] ?? null) === 'date' && $raw instanceof \DateTimeInterface) {
$raw = $raw->format('Y-m-d');
}
$currentValues[$name] = $raw;
}
// Option catalogues (countries + cities + labels) — fetched once per
// page load via the static cache in EntitySectionSchema; multiple
// sections share the result. Skip the call entirely when the section
// has no select-style fields, to save the queries.
$needsCatalogues = collect($fields)->contains(fn ($d) => in_array($d['type'], ['country', 'city', 'select', 'label', 'multiselect', 'group'], true));
$catalogues = $needsCatalogues ? EntitySectionSchema::optionCatalogues($entity) : ['countries' => [], 'cities' => [], 'labels' => [], 'groups' => []];
$sectionDomId = 'sec-' . str_replace('_', '-', $sectionKey);
@endphp
{{-- Title side: the part that triggers collapse. The edit/save
actions live in a sibling div with @click.stop so clicking
them doesn't fold the card open/closed. --}}
{{ $title }}
{{-- View mode: icon-only Edit affordance. Hidden globally
by the body:not(.edit-mode-on) CSS rule unless the
admin has flipped the Edit-Mode toggle in the navbar. --}}
{{-- Edit mode: Cancel + Save (Save shows a spinner when busy). --}}
{{-- View mode — the page supplies whatever rich markup it wants. --}}
{{ $slot }}
{{-- Edit mode — auto-rendered form from the schema. --}}