{{-- Dynamic Elements Rendering --}}
@php
// Normalize elements structure
$elements = data_get($cardSetting, 'elements', []);
if (empty($elements) && is_array($cardSetting)) {
// Backward compatibility for flat structure
$elements = array_filter($cardSetting, function($k) {
return !in_array($k, ['width', 'height', 'bg_type', 'bg_color', 'bg_image', 'layout', 'card', 'status']);
}, ARRAY_FILTER_USE_KEY);
}
// Auto-Deduplicate Logic
// Runs on the final $elements array (whether from 'elements' key or flat structure)
if (!empty($elements)) {
$seen = [];
$deduped = [];
foreach ($elements as $k => $el) {
// Generate a signature for comparison (Data Key + Approx Position)
$dKey = data_get($el, 'data_key', is_string($k) ? $k : 'unknown');
if ($dKey === 'unknown') $dKey = 'txt_'.json_encode($el); // Fallback for pure custom text without key
// Determine if this is a unique field that should strictly not be duplicated (e.g. name, qr, avatar)
// Unless it's a custom text element (starts with txt_) or explicitly 'custom'
$isUniqueField = !str_starts_with($dKey, 'txt_') && $dKey !== 'custom';
if ($isUniqueField) {
// Strict deduplication for fields: Ignore position!
// This fixes "Ghost Elements" where an old element and new element exist for the same field
$sig = $dKey;
} else {
// For custom text or shapes, we trust the ID ($k) to be unique.
// We do NOT want to merge custom elements even if they are in the same position.
// This ensures that if a user places two texts close to each other, both appear.
$sig = $k;
}
if (isset($seen[$sig])) {
// It's a duplicate! Skip it.
continue;
}
$seen[$sig] = true;
$deduped[$k] = $el;
}
// If we actually filtered something, use the filtered list
if (count($deduped) < count($elements)) {
$elements = $deduped;
}
}
@endphp
@foreach($elements as $key => $setting)
@php
$visRaw = data_get($setting, 'visible', true);
$visible = is_string($visRaw)
? !in_array(strtolower($visRaw), ['false', '0', 'no'])
: (bool) $visRaw;
@endphp
@if($visible)
@php
// Check if this is new Design (has 'left') or Legacy (has 'x')
$isNewDesign = isset($setting['left']);
$x = data_get($setting, 'x', 0);
$y = data_get($setting, 'y', 0);
$left = data_get($setting, 'left', 0);
$top = data_get($setting, 'top', 0);
$width = data_get($setting, 'width', null);
$height = data_get($setting, 'height', null);
$size = data_get($setting, 'size', 12);
$color = data_get($setting, 'color', '#000000');
$align = data_get($setting, 'align', 'left');
$font = data_get($setting, 'fontFamily', data_get($setting, 'font', 'inherit'));
$weight = data_get($setting, 'weight', 'normal');
$italic = data_get($setting, 'italic', 'normal');
$posStyle = "";
if ($isNewDesign) {
// New Design: uses px, left/top is top-left corner
$posStyle = "position:absolute; left:{$left}px; top:{$top}px;";
if ($width) $posStyle .= "width:{$width}px;";
if ($height) $posStyle .= "height:{$height}px;";
$posStyle .= "text-align:{$align};";
// Font size in px
$fontSizeUnit = 'px';
} else {
// Legacy: uses mm, x might be center
$posStyle = "position:absolute; left:{$x}mm; top:{$y}mm;";
if ($align === 'center') {
$posStyle .= "transform: translateX(-50%); text-align: center;";
} elseif ($align === 'right') {
$posStyle .= "transform: translateX(-100%); text-align: right;";
} else {
$posStyle .= "text-align: left;";
}
// Font size in pt
$fontSizeUnit = 'pt';
}
@endphp
@if($key === 'avatar' || $key === 'photo' || data_get($setting, 'data_key') === 'avatar' || data_get($setting, 'data_key') === 'photo')
@php
$shape = data_get($setting, 'shape', 'square'); // square, circle
$borderRadius = ($shape === 'circle') ? '50%' : '12px';
// If new design, size might be in width/height
$imgStyle = $posStyle;
if (!$isNewDesign) {
$imgStyle .= "width:{$size}mm; height:{$size}mm;";
}
@endphp
@elseif($key === 'qr_code' || $key === 'qr' || data_get($setting, 'data_key') === 'qr_code' || data_get($setting, 'data_key') === 'qr')
@php
$qrStyle = $posStyle;
if (!$isNewDesign) {
$qrStyle .= "width:{$size}mm; height:{$size}mm;";
}
@endphp
@php
$qrData = data_get($userParticipant, 'id') ?? 0;
// If ActivityUser has unique code, use it.
if (isset($peserta->uid)) $qrData = $peserta->uid;
elseif (isset($peserta->id)) $qrData = "V:" . (data_get($activity, 'id')) . ":" . (data_get($peserta, 'id'));
// For QR size, if new design use width, else use size
$qrSizePx = $isNewDesign ? ($width ?? 100) : ($size * 3.78);
$qrSvg = \SimpleSoftwareIO\QrCode\Facades\QrCode::size(round($qrSizePx))->generate($qrData);
$qrBase64 = base64_encode($qrSvg);
@endphp
@else
{{-- Text Elements --}}
@php
$val = '-';
$fieldType = data_get($setting, 'fieldType');
$dataKey = data_get($setting, 'data_key', $key);
$staticText = data_get($setting, 'text');
if ($fieldType === 'custom' && $staticText) {
$val = $staticText;
} elseif ($fieldType === 'email') {
$val = $userParticipant->email ?? '-';
} elseif ($fieldType === 'phone') {
$val = $profileParticipant->no_hp ?? '-';
} elseif ($fieldType === 'institution') {
$val = $profileParticipant->instansi ?? '-';
} elseif ($fieldType === 'province') {
$val = $provinceParticipant ?? '-';
} elseif ($fieldType === 'regency') {
$val = $regencyParticipant ?? '-';
} elseif ($fieldType === 'district') {
$val = $districtParticipant ?? '-';
} elseif ($dataKey === 'title') {
$val = str_replace(["\r\n","\n"], ' ', ($activity->name ?? 'KARTU PESERTA'));
} elseif ($dataKey === 'name') {
$val = $userParticipant->name ?? '-';
} elseif ($dataKey === 'activity_name') {
$val = $activity->name ?? '-';
} elseif ($dataKey === 'activity_location') {
$val = $activity->location ?? '-';
} elseif ($dataKey === 'activity_time') {
try {
$startDate = $activity->date ?? $activity->start_date ?? null;
$endDate = $activity->end_date ?? null;
$startTime = $activity->time ?? $activity->start_time ?? null;
$endTime = $activity->end_time ?? null;
$fmtDate = function($d){
if (!$d) return null;
if ($d instanceof \Carbon\Carbon) return $d->format('d M Y');
$c = \Carbon\Carbon::parse($d);
return $c->format('d M Y');
};
$fmtTime = function($t){
if (!$t) return null;
if ($t instanceof \Carbon\Carbon) return $t->format('H:i');
$str = (string)$t;
$parts = explode(':', $str);
$h = str_pad($parts[0] ?? '', 2, '0', STR_PAD_LEFT);
$m = str_pad($parts[1] ?? '00', 2, '0', STR_PAD_LEFT);
return $h.':'.$m;
};
$d1 = $fmtDate($startDate);
$d2 = $fmtDate($endDate);
$dateStr = $d1 && $d2 && $d1 !== $d2 ? ($d1.' - '.$d2) : ($d1 ?: ($d2 ?: ''));
$t1 = $fmtTime($startTime);
$t2 = $fmtTime($endTime);
$timeStr = $t1 && $t2 ? ($t1.' - '.$t2) : ($t1 ?: '');
$val = trim(($dateStr ? $dateStr : '') . ($timeStr ? (' '.$timeStr) : ''));
if ($val === '') $val = '-';
} catch (\Throwable $e) {
$val = '-';
}
} elseif ($dataKey === 'status') {
$isCommittee = $activity->canManageRegistration(data_get($userParticipant, 'id'));
$val = $isCommittee ? 'PANITIA' : 'PESERTA';
} elseif ($dataKey === 'role') {
$val = $userParticipant->display_role ?? data_get($peserta, 'role') ?? data_get($peserta, 'position') ?? 'Peserta';
} elseif ($dataKey === 'id_number') {
$val = data_get($peserta, 'participant_number') ?? data_get($peserta, 'id') ?? '-';
} elseif (isset($peserta->$dataKey)) {
$val = $peserta->$dataKey;
} elseif (isset($userParticipant->$dataKey)) {
$val = $userParticipant->$dataKey;
} elseif (isset($profileParticipant->$dataKey)) {
$val = $profileParticipant->$dataKey;
} elseif (isset($peserta->custom_data) && is_array($peserta->custom_data) && isset($peserta->custom_data[$dataKey])) {
$val = $peserta->custom_data[$dataKey];
} elseif (isset($profileParticipant->additional_data) && is_array($profileParticipant->additional_data) && isset($profileParticipant->additional_data[$dataKey])) {
$val = $profileParticipant->additional_data[$dataKey];
}
// Handle object values (like relationships)
if (is_object($val)) {
$val = $val->name ?? '-';
}
@endphp
@php
$justify = $align === 'center' ? 'center' : ($align === 'right' ? 'flex-end' : 'flex-start');
$explicitHeight = $height ? "{$height}px" : ($isNewDesign ? (isset($size) ? (round(($size ?: 12) * 1.2).'px') : null) : null);
$extraStyle = $explicitHeight ? "height:{$explicitHeight};" : "";
@endphp
{{ $val }}
@endif
@endif
@endforeach