done soal
This commit is contained in:
parent
b6677d9103
commit
a672d8f606
@ -75,6 +75,25 @@ class SoalController extends Controller
|
||||
return $detail;
|
||||
});
|
||||
|
||||
$groupInfoByHal = [];
|
||||
foreach ($detailSoal as $detail) {
|
||||
$halValue = (int) ($detail->hal ?? $daftarHal->first());
|
||||
if (!array_key_exists($halValue, $groupInfoByHal)) {
|
||||
$groupInfoByHal[$halValue] = [
|
||||
'nama' => $detail->group_nama,
|
||||
'keterangan' => $detail->group_keterangan,
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($groupInfoByHal[$halValue]['nama']) && !empty($detail->group_nama)) {
|
||||
$groupInfoByHal[$halValue]['nama'] = $detail->group_nama;
|
||||
}
|
||||
|
||||
if (empty($groupInfoByHal[$halValue]['keterangan']) && !empty($detail->group_keterangan)) {
|
||||
$groupInfoByHal[$halValue]['keterangan'] = $detail->group_keterangan;
|
||||
}
|
||||
}
|
||||
$soal->setRelation('soalDetail', $detailSoal);
|
||||
|
||||
$halPertama = $daftarHal->first() ?? $hal;
|
||||
@ -104,6 +123,7 @@ class SoalController extends Controller
|
||||
'prefillJawaban' => $prefillJawaban,
|
||||
'existingJawaban' => $existingJawaban,
|
||||
'formLocked' => $formLocked,
|
||||
'groupInfoByHal' => $groupInfoByHal,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@ -193,6 +193,8 @@
|
||||
$formLocked = $formLocked ?? false;
|
||||
$prefillJawaban = $prefillJawaban ?? [];
|
||||
$existingJawaban = $existingJawaban ?? [];
|
||||
$groupInfoByHal = $groupInfoByHal ?? [];
|
||||
$currentGroupInfo = $groupInfoByHal[$hal] ?? ['nama' => null, 'keterangan' => null];
|
||||
@endphp
|
||||
|
||||
<div class="py-4">
|
||||
@ -224,6 +226,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@php
|
||||
$groupNamaAktif = $currentGroupInfo['nama'] ?? null;
|
||||
$groupKeteranganAktif = $currentGroupInfo['keterangan'] ?? null;
|
||||
$groupNamaLabel = $groupNamaAktif ?: '-';
|
||||
$groupKeteranganLabel = $groupKeteranganAktif ?: '-';
|
||||
$shouldHideGroupCard = ($groupNamaLabel === '-' && $groupKeteranganLabel === '-');
|
||||
@endphp
|
||||
<div class="card border-0 shadow-sm mb-4 {{ $shouldHideGroupCard ? 'd-none' : '' }}" id="group_info_card">
|
||||
<div class="card-body">
|
||||
<h6 class="mb-2 text-primary" id="group-info-nama">{{ $groupNamaLabel }}</h6>
|
||||
<p class="mb-0 text-body" id="group-info-keterangan">{{ $groupKeteranganLabel }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@if ($hal === $halPertama)
|
||||
<div class="card border-0 shadow-sm mb-4" id="head_soal">
|
||||
<div class="card-body">
|
||||
@ -254,7 +269,7 @@
|
||||
<small class="text-muted" id="summary-hal">Halaman {{ $hal }} dari {{ $listHal->count() }}</small>
|
||||
</div>
|
||||
|
||||
<form id="form-soal" method="POST" action="{{ route('soal.store') }}" data-hal-list='@json($listHal->values())' data-form-locked="{{ $formLocked ? '1' : '0' }}">
|
||||
<form id="form-soal" method="POST" action="{{ route('soal.store') }}" data-hal-list='@json($listHal->values())' data-form-locked="{{ $formLocked ? '1' : '0' }}" data-group-info='@json($groupInfoByHal)'>
|
||||
@csrf
|
||||
<input type="hidden" name="lms_mutu_soal_id" value="{{ $soal->id }}">
|
||||
<input type="hidden" name="hal" id="input-hal" value="{{ $hal }}">
|
||||
@ -263,20 +278,62 @@
|
||||
$questionCounter = 0;
|
||||
$groupedQuestionDetails = [];
|
||||
$groupIndexMap = [];
|
||||
$isLainnyaLabel = function ($value) {
|
||||
if (!is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
$normalized = trim(strtolower($value));
|
||||
if ($normalized === '') {
|
||||
return false;
|
||||
}
|
||||
return $normalized === 'lainnya'
|
||||
|| str_contains($normalized, 'lainnya')
|
||||
|| str_contains($normalized, 'other');
|
||||
};
|
||||
$isTidakBerlakuTidakTahuLabel = function ($value) {
|
||||
if (!is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
$normalized = trim(strtolower(preg_replace('/\s+/', ' ', $value)));
|
||||
if ($normalized === '') {
|
||||
return false;
|
||||
}
|
||||
$hasTidakBerlakuTidakTahu = str_contains($normalized, 'tidak berlaku') && str_contains($normalized, 'tidak tahu');
|
||||
return $hasTidakBerlakuTidakTahu || str_contains($normalized, 'sebutkan alasan');
|
||||
};
|
||||
$isOtherOptionLabel = function ($value) use ($isLainnyaLabel, $isTidakBerlakuTidakTahuLabel) {
|
||||
if (!is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
return $isLainnyaLabel($value) || $isTidakBerlakuTidakTahuLabel($value);
|
||||
};
|
||||
foreach ($soal->soalDetail as $detailItem) {
|
||||
$detailConfigItem = json_decode($detailItem->soal, true) ?? [];
|
||||
$detailHalValue = $detailItem->hal ?? $listHal->first();
|
||||
$questionNumberValue = $detailConfigItem['no'] ?? null;
|
||||
if (is_string($questionNumberValue)) {
|
||||
$questionNumberValue = trim($questionNumberValue);
|
||||
}
|
||||
$hasNumberValue = $questionNumberValue !== null && $questionNumberValue !== '';
|
||||
$groupNumberNormalized = null;
|
||||
if ($hasNumberValue) {
|
||||
$compactedNumber = strtolower(preg_replace('/[^a-z0-9]/i', '', (string) $questionNumberValue));
|
||||
if (preg_match('/^(\d+)[a-z]+$/', $compactedNumber, $numberMatch)) {
|
||||
$groupNumberNormalized = $numberMatch[1];
|
||||
} elseif (preg_match('/^(\d+)$/', $compactedNumber, $numberMatch)) {
|
||||
$groupNumberNormalized = $numberMatch[1];
|
||||
}
|
||||
}
|
||||
$groupNumberDisplay = $hasNumberValue ? ($groupNumberNormalized ?? $questionNumberValue) : null;
|
||||
$groupKey = $hasNumberValue
|
||||
? $detailHalValue . '|' . $questionNumberValue
|
||||
? $detailHalValue . '|' . ($groupNumberNormalized ?? (string) $questionNumberValue)
|
||||
: 'detail_' . $detailItem->id;
|
||||
|
||||
if (!array_key_exists($groupKey, $groupIndexMap)) {
|
||||
$groupIndexMap[$groupKey] = count($groupedQuestionDetails);
|
||||
$groupedQuestionDetails[] = [
|
||||
'hal' => $detailHalValue,
|
||||
'number' => $hasNumberValue ? $questionNumberValue : null,
|
||||
'number' => $groupNumberDisplay,
|
||||
'items' => [],
|
||||
];
|
||||
}
|
||||
@ -348,28 +405,35 @@
|
||||
$oldOtherAnswer = $currentAnswer;
|
||||
}
|
||||
$showLainnya = $isCustomCurrentAnswer
|
||||
|| (is_string($currentAnswer) && stripos($currentAnswer, 'lainnya') !== false)
|
||||
|| (is_string($currentAnswer) && $isOtherOptionLabel($currentAnswer))
|
||||
|| (!empty($oldOtherAnswer));
|
||||
$detailHal = $detail->hal ?? $listHal->first();
|
||||
$optionsCount = is_array($options) ? count($options) : 0;
|
||||
$hasLainnyaOption = collect($options)->contains(function ($optionItem) {
|
||||
return is_string($optionItem) && stripos($optionItem, 'lainnya') !== false;
|
||||
$hasCustomOtherOption = collect($options)->contains(function ($optionItem) use ($isOtherOptionLabel) {
|
||||
return $isOtherOptionLabel($optionItem);
|
||||
});
|
||||
if (!$hasLainnyaOption && $type === 'option_with_other') {
|
||||
if (!$hasCustomOtherOption && $type === 'option_with_other') {
|
||||
$options[] = 'Lainnya';
|
||||
$optionsCount = count($options);
|
||||
$hasLainnyaOption = true;
|
||||
$hasCustomOtherOption = true;
|
||||
}
|
||||
$lainnyaOptionLabel = collect($options)->first(function ($optionItem) use ($isLainnyaLabel) {
|
||||
return $isLainnyaLabel($optionItem);
|
||||
});
|
||||
$tidakBerlakuOptionLabel = collect($options)->first(function ($optionItem) use ($isTidakBerlakuTidakTahuLabel) {
|
||||
return $isTidakBerlakuTidakTahuLabel($optionItem);
|
||||
});
|
||||
$otherOptionHintLabel = $lainnyaOptionLabel ?: $tidakBerlakuOptionLabel;
|
||||
$shouldForceOtherSelection = $hasCustomOtherOption && $showLainnya;
|
||||
$isConsentQuestion = !empty($detailConfig['persetujuan_form']);
|
||||
$shouldForceLainnyaSelection = $hasLainnyaOption && $showLainnya;
|
||||
$dualFormConfig = $detailConfig['dual_form'] ?? null;
|
||||
$useDualForm = $type === 'dual_form' || (!empty($dualFormConfig) && $dualFormConfig !== false);
|
||||
$dualYearOld = null;
|
||||
$dualMonthOld = null;
|
||||
$questionNumber = $detailConfig['no'] ?? '';
|
||||
$hasGroupNumber = $groupNumber !== null && $groupNumber !== '';
|
||||
$badgeNumber = $hasGroupNumber ? $groupNumber : $questionNumber;
|
||||
$shouldShowNumber = $badgeNumber !== null && $badgeNumber !== '' && (!$hasGroupNumber || $loop->first);
|
||||
$displayNumber = $questionNumber !== '' ? $questionNumber : ($hasGroupNumber ? $groupNumber : '');
|
||||
$shouldShowNumber = $displayNumber !== null && $displayNumber !== '';
|
||||
$rangeMin = null;
|
||||
$rangeMax = null;
|
||||
$rangeStep = 1;
|
||||
@ -490,9 +554,9 @@
|
||||
<div class="col-md-6 question-text-col">
|
||||
<div class="d-flex align-items-center gap-3 mb-1">
|
||||
@if ($shouldShowNumber)
|
||||
<span class="badge rounded-pill bg-label-primary fs-6">{{ $badgeNumber }}</span>
|
||||
<span class="badge rounded-pill bg-label-primary fs-6">{{ $displayNumber }}</span>
|
||||
@elseif($hasGroupNumber)
|
||||
<span class="badge rounded-pill bg-label-primary fs-6 badge-placeholder" aria-hidden="true">{{ $badgeNumber }}</span>
|
||||
<span class="badge rounded-pill bg-label-primary fs-6 badge-placeholder" aria-hidden="true">{{ $displayNumber }}</span>
|
||||
@endif
|
||||
<h5 class="fw-semibold mb-0">{{ $pertanyaan }}</h5>
|
||||
</div>
|
||||
@ -637,9 +701,9 @@
|
||||
@php
|
||||
$optionId = 'jawaban-' . $detail->id . '-' . $optionIndex;
|
||||
$optionLabel = is_scalar($option) ? (string) $option : '';
|
||||
$isLainnya = stripos($optionLabel, 'lainnya') !== false;
|
||||
$optionValue = $isLainnya && $oldOtherAnswer ? $oldOtherAnswer : $optionLabel;
|
||||
$shouldCheck = $currentAnswer === $optionValue || ($isLainnya && $shouldForceLainnyaSelection);
|
||||
$isOtherOption = $isOtherOptionLabel($optionLabel);
|
||||
$optionValue = $isOtherOption && $oldOtherAnswer ? $oldOtherAnswer : $optionLabel;
|
||||
$shouldCheck = $currentAnswer === $optionValue || ($isOtherOption && $shouldForceOtherSelection);
|
||||
@endphp
|
||||
<div class="form-check mb-2" data-option-item>
|
||||
<input class="form-check-input @error('jawaban.' . $detail->id) is-invalid @enderror"
|
||||
@ -648,7 +712,7 @@
|
||||
id="{{ $optionId }}"
|
||||
value="{{ $optionValue }}"
|
||||
data-original-value="{{ $optionLabel }}"
|
||||
data-lainnya-radio="{{ $isLainnya ? $detail->id : '' }}"
|
||||
data-lainnya-radio="{{ $isOtherOption ? $detail->id : '' }}"
|
||||
data-field-hal="{{ $detailHal }}"
|
||||
@if ($isConsentQuestion) data-consent-input="1" required @endif
|
||||
@if($formLocked) disabled @endif
|
||||
@ -658,7 +722,7 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if ($isLainnya)
|
||||
@if ($isOtherOption)
|
||||
@php
|
||||
$lainnyaWrapperRendered = true;
|
||||
@endphp
|
||||
@ -675,9 +739,9 @@
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@if ($hasLainnyaOption || $type === 'option_with_other')
|
||||
@if ($otherOptionHintLabel)
|
||||
<small class="form-text text-muted">
|
||||
Jika jawaban yang Anda cari tidak ada di daftar, pilih opsi <strong>"Lainnya"</strong> lalu isi sesuai kebutuhan.
|
||||
Jika jawaban yang Anda cari tidak ada di daftar, pilih opsi <strong>"{{ $otherOptionHintLabel }}"</strong> lalu isi sesuai kebutuhan.
|
||||
</small>
|
||||
@endif
|
||||
<div class="text-muted small mt-2" data-option-empty="{{ $detail->id }}" style="display: none;">
|
||||
@ -794,8 +858,25 @@
|
||||
const nonConsentFields = document.querySelectorAll('[data-field-hal]:not([data-consent-input="1"])');
|
||||
const consentFields = document.querySelectorAll('[data-consent-input="1"][name]');
|
||||
const headSoalCard = document.getElementById('head_soal');
|
||||
const consentNegativeKeywords = ['tidak', 'tidak setuju'];
|
||||
const consentNegativeKeywords = ['tidak', 'tidak setuju', 'saya tidak bersedia'];
|
||||
let immediateSubmitActive = false;
|
||||
let groupInfoMap = {};
|
||||
try {
|
||||
groupInfoMap = JSON.parse(form.dataset.groupInfo || '{}');
|
||||
} catch (error) {
|
||||
groupInfoMap = {};
|
||||
}
|
||||
if (Array.isArray(groupInfoMap)) {
|
||||
groupInfoMap = groupInfoMap.reduce(function (acc, value, index) {
|
||||
if (value && typeof value === 'object') {
|
||||
acc[index] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
const groupInfoCard = document.getElementById('group_info_card');
|
||||
const groupInfoNama = document.getElementById('group-info-nama');
|
||||
const groupInfoKeterangan = document.getElementById('group-info-keterangan');
|
||||
|
||||
function normalizeOtherValue(value) {
|
||||
return (value || '').toString().trim().toLowerCase();
|
||||
@ -806,6 +887,9 @@
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
const includesTidakBerlakuTidakTahu =
|
||||
normalized.includes('tidak berlaku') && normalized.includes('tidak tahu');
|
||||
const includesSebutkanAlasan = normalized.includes('sebutkan alasan');
|
||||
return normalized === 'lainnya'
|
||||
|| normalized === 'lainnya (sebutkan)'
|
||||
|| normalized === 'lainnya/other'
|
||||
@ -813,7 +897,9 @@
|
||||
|| normalized === 'other'
|
||||
|| normalized === 'others'
|
||||
|| normalized.includes('lainnya')
|
||||
|| normalized.includes('other');
|
||||
|| normalized.includes('other')
|
||||
|| includesTidakBerlakuTidakTahu
|
||||
|| includesSebutkanAlasan;
|
||||
}
|
||||
|
||||
function getLabelTextByInput(input) {
|
||||
@ -841,6 +927,7 @@
|
||||
setupConsentWatcher();
|
||||
updateQuestionVisibility();
|
||||
updateNavigationUI();
|
||||
updateGroupInfoUI();
|
||||
|
||||
navHalButtons.forEach(function (button) {
|
||||
button.addEventListener('click', function () {
|
||||
@ -916,6 +1003,7 @@
|
||||
}
|
||||
updateQuestionVisibility();
|
||||
updateNavigationUI();
|
||||
updateGroupInfoUI();
|
||||
scrollPageToTop();
|
||||
}
|
||||
|
||||
@ -999,6 +1087,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
function updateGroupInfoUI() {
|
||||
if (!groupInfoCard || !groupInfoNama || !groupInfoKeterangan) {
|
||||
return;
|
||||
}
|
||||
const info = (groupInfoMap && groupInfoMap[currentHal]) || {};
|
||||
const namaText = (info.nama || '').toString().trim() || '-';
|
||||
const ketText = (info.keterangan || '').toString().trim() || '-';
|
||||
groupInfoNama.textContent = namaText;
|
||||
groupInfoKeterangan.textContent = ketText;
|
||||
const shouldHide = namaText === '-' && ketText === '-';
|
||||
groupInfoCard.classList.toggle('d-none', shouldHide);
|
||||
}
|
||||
|
||||
function setupLainnyaInputs() {
|
||||
const radios = form.querySelectorAll('input[type="radio"][name^="jawaban["]');
|
||||
radios.forEach(function (radio) {
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
@section('content')
|
||||
<div class="py-5">
|
||||
<div class="text-center mb-5">
|
||||
<h2 class="fw-bold mb-2">Selamat Datang di Survei Mutu</h2>
|
||||
<h2 class="fw-bold mb-2">Selamat Datang di Survei Komite Mutu Rumah Sakit</h2>
|
||||
<p class="text-muted mb-0">Silakan pilih kuesioner yang ingin Anda isi. Pastikan data yang diberikan sesuai kondisi unit kerja Anda.</p>
|
||||
</div>
|
||||
@if (session('success'))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user