diff --git a/app/config/app.php b/app/config/app.php index f5f064b..0cf9a0b 100644 --- a/app/config/app.php +++ b/app/config/app.php @@ -3,5 +3,5 @@ "latte" => true, "locale" => "tr_TR.utf8", "timezone" => "Europe/Istanbul", - "mode" => "Production" #Development or Production + "mode" => "development" #Development or Production ]; \ No newline at end of file diff --git a/app/config/database.php b/app/config/database.php index 297a7d9..7ab7ad7 100644 --- a/app/config/database.php +++ b/app/config/database.php @@ -7,5 +7,7 @@ "host" => "localhost", "prefix" => "", "user" => "root", - "password" => "" + "password" => "", + "cache" => false, + "cacheTime" => 60, ]; diff --git a/app/controllers/Participate.php b/app/controllers/Participate.php index 69db12e..d504b8e 100644 --- a/app/controllers/Participate.php +++ b/app/controllers/Participate.php @@ -277,8 +277,8 @@ public function apply() $user = session_get("participator"); if ($survey->verifyPhone) { - if (Participator::checkSurveyIsParticipated($user->personalId, true)) - warning("Bu anketi daha önce zaten cevapladınız!"); + if (Participator::checkSurveyIsParticipated($surveyId, (string) $user->personalId, true)) + warninglang("participate.already.answered"); } $post = Request::post(); @@ -289,38 +289,98 @@ public function apply() $formData = json_decode($survey->data); - foreach ($formData as $key => $value) { - if ($value->type == "description") + $slugToQuestion = []; + $slugToSection = []; + $sectionSlugs = []; + $activeSectionSlug = null; + foreach ($formData as $q) { + if (! isset($q->slug)) + continue; + $slugToQuestion[$q->slug] = $q; + if ($q->type === "section") { + $activeSectionSlug = $q->slug; + $sectionSlugs[$q->slug] = true; + $slugToSection[$q->slug] = $q->slug; continue; + } + $slugToSection[$q->slug] = $activeSectionSlug; + } - // Koşullu soru kontrolü - tüm soru tipleri için - $index = -1; - $hasCondition = false; - - foreach ($formData as $dkey => $dvalue) { - // Eğer bu soru koşula sahipse - if (!empty($dvalue->conditions)) { - foreach ($dvalue->conditions as $i => $p) { - if ($p->value == $value->slug) { - $hasCondition = true; // Bu soru bir koşula bağlı - $parentAnswer = $post->{$dvalue->slug} ?? null; - - if ($p->index == $parentAnswer) { - $index = $i; - break 2; // iki foreach'ten çık - } - } + $isConditionSatisfied = function ($parentQ, $cond) use ($post) { + if (! $parentQ || ! $cond) + return false; + $parentSlug = $parentQ->slug ?? ""; + if ($parentSlug === "") + return false; + $expected = (string) ($cond->index ?? ""); + if ($parentQ->type === "radio" || $parentQ->type === "select") { + $actual = isset($post->{$parentSlug}) ? (string) $post->{$parentSlug} : ""; + return $actual !== "" && $actual === $expected; + } + if ($parentQ->type === "checkbox") { + $key = $parentSlug . $expected; + return isset($post->{$key}); + } + return false; + }; + + $isSlugVisible = function ($slug) use ($formData, $slugToSection, $sectionSlugs, $isConditionSatisfied) { + if (! $slug) + return true; + + $directRules = []; + foreach ($formData as $parentQ) { + if (empty($parentQ->conditions)) + continue; + foreach ($parentQ->conditions as $cond) { + if (($cond->value ?? null) == $slug) + $directRules[] = [$parentQ, $cond]; + } + } + if (! empty($directRules)) { + $ok = false; + foreach ($directRules as [$pQ, $cond]) { + if ($isConditionSatisfied($pQ, $cond)) { + $ok = true; + break; } } + if (! $ok) + return false; } - // Eğer koşula bağlıysa ve koşul sağlanmamışsa bu soruyu atla - if ($hasCondition && $index == -1) { - continue; + $sectionSlug = $slugToSection[$slug] ?? null; + if (! $sectionSlug || ! isset($sectionSlugs[$sectionSlug]) || $sectionSlug === $slug) + return true; + + $sectionRules = []; + foreach ($formData as $parentQ) { + if (empty($parentQ->conditions)) + continue; + foreach ($parentQ->conditions as $cond) { + if (($cond->value ?? null) == $sectionSlug) + $sectionRules[] = [$parentQ, $cond]; + } } + if (empty($sectionRules)) + return true; + + foreach ($sectionRules as [$pQ, $cond]) { + if ($isConditionSatisfied($pQ, $cond)) + return true; + } + return false; + }; + + foreach ($formData as $key => $value) { + if ($value->type == "description" || $value->type == "section") + continue; + if (! $isSlugVisible($value->slug)) + continue; switch ($value->type) { case "radio": + case "sentiment_scale": $rules[$value->slug] = [ "name" => $value->title, #"required" => $value->isRequired, @@ -344,7 +404,7 @@ public function apply() $validate2 = ! in_array(true, $actions); if ($validate2) - $errors[] = $value->title . " sorusunu cevaplayınız!"; + $errors[] = lang("survey.validation.checkbox_required", strip_tags($value->title)); } break; @@ -360,6 +420,83 @@ public function apply() $rules[$value->slug]["required"] = $value->isRequired; break; + + case "short_text": + $maxLen = isset($value->maxLength) ? (int) $value->maxLength : 255; + if ($maxLen < 1) + $maxLen = 255; + if ($maxLen > 4000) + $maxLen = 4000; + $rules[$value->slug] = [ + "name" => $value->title . "
", + "max" => $maxLen, + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; + + case "email": + $rules[$value->slug] = [ + "name" => $value->title . "
", + "max" => 255, + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; + + case "url": + $rules[$value->slug] = [ + "name" => $value->title . "
", + "max" => 2048, + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; + + case "phone": + $rules[$value->slug] = [ + "name" => $value->title . "
", + "max" => 32, + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; + + case "date": + case "time": + $rules[$value->slug] = [ + "name" => $value->title . "
", + "max" => 32, + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; + + case "number": + $rules[$value->slug] = [ + "name" => $value->title . "
", + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; + + case "select": + $rules[$value->slug] = [ + "name" => $value->title . "
", + "min" => 0, + "max" => max(0, count($value->answers) - 1), + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; + + case "scale": + $rules[$value->slug] = [ + "name" => $value->title . "
", + ]; + if ($value->isRequired) + $rules[$value->slug]["required"] = true; + break; } } @@ -371,6 +508,61 @@ public function apply() if ($validate) warning($validate); + foreach ($formData as $value) { + if ($value->type === "description" || $value->type === "section") + continue; + if (! $isSlugVisible($value->slug)) + continue; + $slug = $value->slug; + if ($value->type === "email") { + $raw = isset($post->$slug) ? trim((string) $post->$slug) : ""; + if ($raw !== "" && ! validate_email($raw)) + warning(lang("validation.email_error")); + } + if ($value->type === "url") { + $raw = isset($post->$slug) ? trim((string) $post->$slug) : ""; + if ($raw !== "" && ! filter_var($raw, FILTER_VALIDATE_URL)) + warning(lang("validation.url.error", strip_tags($value->title))); + } + if ($value->type === "phone") { + $raw = isset($post->$slug) ? trim((string) $post->$slug) : ""; + if ($raw === "") + continue; + $digits = preg_replace('/\D+/', '', $raw); + if ($digits !== "" && strlen($digits) < 10) + warning(lang("validation.phone.error", strip_tags($value->title))); + } + if ($value->type === "number") { + $raw = isset($post->$slug) ? trim((string) $post->$slug) : ""; + if ($raw === "") + continue; + if (! is_numeric($raw)) + warning(lang("survey.validation.number_range", strip_tags($value->title))); + $num = 0 + $raw; + if (isset($value->numMin) && is_numeric($value->numMin) && $num < (float) $value->numMin) + warning(lang("survey.validation.number_range", strip_tags($value->title))); + if (isset($value->numMax) && is_numeric($value->numMax) && $num > (float) $value->numMax) + warning(lang("survey.validation.number_range", strip_tags($value->title))); + } + if ($value->type === "scale") { + $raw = isset($post->$slug) ? trim((string) $post->$slug) : ""; + if ($raw === "") + continue; + if (! is_numeric($raw)) + warning(lang("survey.validation.scale_range", strip_tags($value->title))); + $num = (float) $raw; + $smin = isset($value->scaleMin) ? (float) $value->scaleMin : 1; + $smax = isset($value->scaleMax) ? (float) $value->scaleMax : 5; + if ($smin > $smax) { + $t = $smin; + $smin = $smax; + $smax = $t; + } + if ($num < $smin || $num > $smax) + warning(lang("survey.validation.scale_range", strip_tags($value->title))); + } + } + $result = false; if ($survey->verifyPhone) { $result = $this->db->from("answers") diff --git a/app/controllers/Reports.php b/app/controllers/Reports.php index 7ec10bc..72c4265 100644 --- a/app/controllers/Reports.php +++ b/app/controllers/Reports.php @@ -44,7 +44,7 @@ public function watch(int $surveyId) ->from("personals") ->where("id", "!=", "0") ->where("status", "=", 1) - ->orderBy("fullName", "ASC") + ->orderBy("fullname", "ASC") ->results(); $args = [ @@ -54,7 +54,8 @@ public function watch(int $surveyId) "anonymous" => $survey->anonymous, "surveyId" => $surveyId, "departmentList" => $departmentList, - "personList" => $personList + "personList" => $personList, + "reportEmptyLabel" => lang("survey.report.empty"), ]; if (!$survey->anonymous) diff --git a/app/controllers/surveys.php b/app/controllers/surveys.php index e19bae5..f94d8f3 100644 --- a/app/controllers/surveys.php +++ b/app/controllers/surveys.php @@ -8,6 +8,37 @@ class Surveys extends Controller { + /** Strings for public/js/app.js (survey builder). */ + protected function surveyBuilderI18nJson(): string + { + $keys = [ + 'survey.builder.questions', 'survey.builder.create', 'survey.builder.developing', 'survey.builder.preview', + 'survey.builder.required', 'survey.builder.horizontal_layout', 'survey.builder.condition_none', 'survey.builder.close', + 'survey.builder.radio_list', 'survey.builder.checkbox_list', 'survey.builder.textarea', 'survey.builder.description', + 'survey.builder.short_text', 'survey.builder.email', 'survey.builder.phone', 'survey.builder.url', 'survey.builder.date', 'survey.builder.time', + 'survey.builder.number', 'survey.builder.select', 'survey.builder.scale', + 'survey.builder.star_rating', 'survey.builder.like_dislike_scale', 'survey.builder.single_choice_scale', + 'survey.builder.negative_label', 'survey.builder.positive_label', 'survey.builder.negative_value', 'survey.builder.positive_value', + 'survey.builder.neutral_value', 'survey.builder.steps', 'survey.builder.unsectioned_zone', + 'survey.builder.section', 'survey.builder.new_question', 'survey.builder.new_answer', + 'survey.builder.desc_subtype.info', 'survey.builder.desc_subtype.warning', 'survey.builder.desc_subtype.success', 'survey.builder.desc_subtype.danger', + 'survey.builder.max_length', 'survey.builder.min', 'survey.builder.max', 'survey.builder.step', + 'survey.builder.scale_from', 'survey.builder.scale_to', 'survey.builder.label_left', 'survey.builder.label_right', + 'survey.builder.cover_photo', 'survey.builder.upload_file', 'survey.builder.drag_drop', 'survey.builder.image_formats', + 'survey.builder.about_survey', 'survey.builder.about_hint', 'survey.builder.cancel', 'survey.builder.save', + 'survey.builder.anonymous_publish', 'survey.builder.apply_template', 'survey.builder.template_blank', + 'survey.builder.template_satisfaction', 'survey.builder.template_contact', + 'survey.builder.template_event_registration', 'survey.builder.template_customer_feedback', 'survey.builder.template_employee_pulse', 'survey.builder.template_lead_capture', + 'survey.builder.draft_banner', 'survey.builder.section_subtitle', + 'survey.builder.phone_placeholder', 'survey.builder.back', 'survey.builder.next', 'survey.builder.finish', + ]; + $out = []; + foreach ($keys as $k) { + $out[$k] = lang($k); + } + return json_encode($out, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS); + } + #[route(method: route::get | route::xhr_get, session: "user")] public function index() { @@ -30,7 +61,10 @@ public function create() "url" => "apply", "surveyFormTitle" => lang("create.survey"), "user" => User::info(), - "showIfOnEditMode" => false + "showIfOnEditMode" => false, + "surveyBuilderI18nJson" => $this->surveyBuilderI18nJson(), + "isSurveyEdit" => false, + "isSurveyCreateJs" => "true", ]); } @@ -178,7 +212,10 @@ public function edit(int $surveyId) "user" => User::info(), "surveyFormTitle" => $surveyFormTitle, "url" => $isOnEditMode ? "apply/$surveyId" : "apply", - "showIfOnEditMode" => $isOnEditMode ? "" : "" + "showIfOnEditMode" => $isOnEditMode ? "" : "", + "surveyBuilderI18nJson" => $this->surveyBuilderI18nJson(), + "isSurveyEdit" => true, + "isSurveyCreateJs" => "false", ]); } diff --git a/app/lang/en_US.php b/app/lang/en_US.php index d886c1f..56855f7 100644 --- a/app/lang/en_US.php +++ b/app/lang/en_US.php @@ -116,5 +116,83 @@ "participate.sms.otp.body" => "Your verification code for the survey system: %s", "participate.sms.otp.body.ascii" => "Survey verification code: %s", "participate.email.otp.subject" => "Survey Verification Code", - "participate.email.otp.body" => "Your verification code for survey participation: %s" + "participate.email.otp.body" => "Your verification code for survey participation: %s", + "participate.submit" => "Submit", + + "survey.report.filled" => "Filled", + "survey.report.empty" => "Empty", + + "survey.validation.checkbox_required" => "Please answer the question: %s", + "survey.validation.number_range" => "Enter a valid number for «%s».", + "survey.validation.scale_range" => "Choose a value within the scale for «%s».", + + "survey.builder.questions" => "Questions", + "survey.builder.create" => "Add", + "survey.builder.developing" => "Edit", + "survey.builder.preview" => "Preview", + "survey.builder.required" => "Required", + "survey.builder.horizontal_layout" => "Horizontal layout", + "survey.builder.condition_none" => "None", + "survey.builder.close" => "Close", + "survey.builder.radio_list" => "Multiple choice", + "survey.builder.checkbox_list" => "Checkboxes", + "survey.builder.textarea" => "Paragraph", + "survey.builder.description" => "Description / info box", + "survey.builder.short_text" => "Short answer", + "survey.builder.email" => "Email", + "survey.builder.phone" => "Phone", + "survey.builder.url" => "URL", + "survey.builder.date" => "Date", + "survey.builder.time" => "Time", + "survey.builder.number" => "Number", + "survey.builder.select" => "Dropdown", + "survey.builder.scale" => "Linear scale", + "survey.builder.star_rating" => "Star rating (1-5)", + "survey.builder.like_dislike_scale" => "Like / Dislike scale", + "survey.builder.single_choice_scale" => "Single-choice scale range (1-10)", + "survey.builder.negative_label" => "Negative value", + "survey.builder.positive_label" => "Positive value", + "survey.builder.negative_value" => "Disliked", + "survey.builder.positive_value" => "Liked", + "survey.builder.neutral_value" => "Neutral", + "survey.builder.steps" => "Steps", + "survey.builder.unsectioned_zone" => "Unsectioned area (drop question here)", + "survey.builder.section" => "Section title", + "survey.builder.new_question" => "New question", + "survey.builder.new_answer" => "New option", + "survey.builder.desc_subtype.info" => "Info", + "survey.builder.desc_subtype.warning" => "Warning", + "survey.builder.desc_subtype.success" => "Success", + "survey.builder.desc_subtype.danger" => "Danger", + "survey.builder.max_length" => "Max length", + "survey.builder.min" => "Min", + "survey.builder.max" => "Max", + "survey.builder.step" => "Step", + "survey.builder.scale_from" => "Scale from", + "survey.builder.scale_to" => "Scale to", + "survey.builder.label_left" => "Left label", + "survey.builder.label_right" => "Right label", + "survey.builder.cover_photo" => "Cover image", + "survey.builder.upload_file" => "Upload a file", + "survey.builder.drag_drop" => "or drag and drop", + "survey.builder.image_formats" => "PNG, JPG, GIF up to 10MB", + "survey.builder.about_survey" => "About the survey", + "survey.builder.about_hint" => "Write a few sentences about the survey.", + "survey.builder.cancel" => "Cancel", + "survey.builder.save" => "Save", + "survey.builder.anonymous_publish" => "Publish as anonymous survey", + "survey.builder.apply_template" => "Template", + "survey.builder.template_blank" => "Blank", + "survey.builder.template_satisfaction" => "Quick satisfaction", + "survey.builder.template_contact" => "Contact details", + "survey.builder.template_event_registration" => "Event registration", + "survey.builder.template_customer_feedback" => "Customer feedback", + "survey.builder.template_employee_pulse" => "Employee pulse", + "survey.builder.template_lead_capture" => "Lead / quote form", + "survey.builder.draft_banner" => "A saved draft was restored.", + "survey.builder.section_subtitle" => "Section subtitle (optional)", + "survey.builder.phone_placeholder" => "+90 5xx xxx xx xx", + "survey.builder.back" => "Back", + "survey.builder.next" => "Next", + "survey.builder.finish" => "Finish", ]; \ No newline at end of file diff --git a/app/lang/tr_TR.php b/app/lang/tr_TR.php index d15eb35..bc26241 100644 --- a/app/lang/tr_TR.php +++ b/app/lang/tr_TR.php @@ -116,5 +116,83 @@ "participate.sms.otp.body" => "Anket sistemine giriş için onay kodu: %s", "participate.sms.otp.body.ascii" => "Anket katilim icin onay kodu: %s", "participate.email.otp.subject" => "Anket Doğrulama Kodu", - "participate.email.otp.body" => "Anket katılımı için doğrulama kodunuz: %s" + "participate.email.otp.body" => "Anket katılımı için doğrulama kodunuz: %s", + "participate.submit" => "Gönder", + + "survey.report.filled" => "Dolu", + "survey.report.empty" => "Boş", + + "survey.validation.checkbox_required" => "%s sorusunu yanıtlayınız!", + "survey.validation.number_range" => "%s için geçerli bir sayı giriniz.", + "survey.validation.scale_range" => "%s için ölçek aralığında bir değer seçiniz.", + + "survey.builder.questions" => "Sorular", + "survey.builder.create" => "Ekle", + "survey.builder.developing" => "Düzenle", + "survey.builder.preview" => "Önizleme", + "survey.builder.required" => "Zorunlu", + "survey.builder.horizontal_layout" => "Yatay olarak diz", + "survey.builder.condition_none" => "Seçili değil", + "survey.builder.close" => "Kapat", + "survey.builder.radio_list" => "Çoktan seçmeli (tek)", + "survey.builder.checkbox_list" => "Çoktan seçmeli (çoklu)", + "survey.builder.textarea" => "Uzun metin", + "survey.builder.description" => "Açıklama / bilgi kutusu", + "survey.builder.short_text" => "Kısa metin", + "survey.builder.email" => "E-posta", + "survey.builder.phone" => "Telefon", + "survey.builder.url" => "URL", + "survey.builder.date" => "Tarih", + "survey.builder.time" => "Saat", + "survey.builder.number" => "Sayı", + "survey.builder.select" => "Açılır liste", + "survey.builder.scale" => "Ölçek (doğrusal)", + "survey.builder.star_rating" => "Yıldız değerlendirme (1-5)", + "survey.builder.like_dislike_scale" => "Beğendim / Beğenmedim ölçeği", + "survey.builder.single_choice_scale" => "Tek seçimli ölçek aralığı (1-10)", + "survey.builder.negative_label" => "Negatif değer", + "survey.builder.positive_label" => "Pozitif değer", + "survey.builder.negative_value" => "Beğenmedim", + "survey.builder.positive_value" => "Beğendim", + "survey.builder.neutral_value" => "Kararsızım", + "survey.builder.steps" => "Adım sayısı", + "survey.builder.unsectioned_zone" => "Bölümsüz alan (soruyu buraya bırak)", + "survey.builder.section" => "Bölüm başlığı", + "survey.builder.new_question" => "Yeni soru", + "survey.builder.new_answer" => "Yeni seçenek", + "survey.builder.desc_subtype.info" => "Bilgi", + "survey.builder.desc_subtype.warning" => "Uyarı", + "survey.builder.desc_subtype.success" => "Başarı", + "survey.builder.desc_subtype.danger" => "Tehlike", + "survey.builder.max_length" => "Maks. uzunluk", + "survey.builder.min" => "Min", + "survey.builder.max" => "Max", + "survey.builder.step" => "Adım", + "survey.builder.scale_from" => "Ölçek başlangıç", + "survey.builder.scale_to" => "Ölçek bitiş", + "survey.builder.label_left" => "Sol etiket", + "survey.builder.label_right" => "Sağ etiket", + "survey.builder.cover_photo" => "Kapak görseli", + "survey.builder.upload_file" => "Dosya yükle", + "survey.builder.drag_drop" => "veya sürükleyip bırakın", + "survey.builder.image_formats" => "PNG, JPG, GIF en fazla 10MB", + "survey.builder.about_survey" => "Anket hakkında", + "survey.builder.about_hint" => "Anket için birkaç cümle yazın.", + "survey.builder.cancel" => "İptal", + "survey.builder.save" => "Kaydet", + "survey.builder.anonymous_publish" => "Anonim anket olarak yayımla", + "survey.builder.apply_template" => "Şablon", + "survey.builder.template_blank" => "Boş şablon", + "survey.builder.template_satisfaction" => "Memnuniyet (kısa)", + "survey.builder.template_contact" => "İletişim bilgisi", + "survey.builder.template_event_registration" => "Etkinlik kaydı", + "survey.builder.template_customer_feedback" => "Müşteri geri bildirimi", + "survey.builder.template_employee_pulse" => "Çalışan nabız anketi", + "survey.builder.template_lead_capture" => "Teklif / lead formu", + "survey.builder.draft_banner" => "Kayıtlı taslak bulundu; alanlar geri yüklendi.", + "survey.builder.section_subtitle" => "Bölüm alt başlığı (isteğe bağlı)", + "survey.builder.phone_placeholder" => "05xx xxx xx xx", + "survey.builder.back" => "Geri", + "survey.builder.next" => "İleri", + "survey.builder.finish" => "Bitir", ]; \ No newline at end of file diff --git a/app/models/Survey.php b/app/models/Survey.php index da417ab..a692b53 100644 --- a/app/models/Survey.php +++ b/app/models/Survey.php @@ -78,7 +78,7 @@ public static function participators(int $surveyId) $participators = []; foreach ($uniqueParticipants as $participant) { $fullData = Database::get() - ->select("answers.*, personals.fullname, personals.department") + ->select("answers.*, personals.fullname, personals.department, personals.phone1, personals.phone2, personals.status") ->from("answers") ->leftJoin("personals", "personals.id = answers.personalId") ->where("answers.id", "=", $participant->maxId) @@ -149,6 +149,20 @@ public static function generateReportData($survey) } $generatedData = []; + $slugToSection = []; + $sectionSlugs = []; + $activeSectionSlug = null; + foreach ($questionData as $q) { + if (! isset($q->slug)) + continue; + if ($q->type === "section") { + $activeSectionSlug = $q->slug; + $sectionSlugs[$q->slug] = true; + $slugToSection[$q->slug] = $q->slug; + continue; + } + $slugToSection[$q->slug] = $activeSectionSlug; + } $groupIndex = 0; #for IK @@ -158,13 +172,24 @@ public static function generateReportData($survey) $groups = ["default"]; $isFirstDescription = true; + $currentGroupName = $groups[$groupIndex] ?? "default"; foreach ($questionData as $question) { + if ($question->type == "section") { + $sectionTitle = trim(strip_tags((string) ($question->title ?? ""))); + if ($sectionTitle === "") + $sectionTitle = "section-" . ($groupIndex + 1); + $currentGroupName = $sectionTitle; + continue; + } + if ($question->type == "description") { if ($isFirstDescription) $isFirstDescription = false; - else + else { $groupIndex++; + $currentGroupName = $groups[$groupIndex] ?? $currentGroupName; + } continue; } @@ -187,7 +212,25 @@ public static function generateReportData($survey) } } - $group0 = $groups[$groupIndex]; + if (! $hasCondition) { + $sectionSlug = $slugToSection[$question->slug] ?? null; + if ($sectionSlug && isset($sectionSlugs[$sectionSlug]) && $sectionSlug !== $question->slug) { + foreach ($questionData as $parentQ) { + if (empty($parentQ->conditions)) + continue; + foreach ($parentQ->conditions as $cond) { + if ($cond->value == $sectionSlug) { + $hasCondition = true; + $parentQuestion = $parentQ; + $parentAnswerIndex = $cond->index; + break 2; + } + } + } + } + } + + $group0 = $currentGroupName ?: ($groups[$groupIndex] ?? "default"); // Radio için tüm katılımcıları döndüren fonksiyon $searchAll = function () use ($question, $answerData, $hasCondition, $parentQuestion, $parentAnswerIndex) { @@ -233,7 +276,7 @@ public static function generateReportData($survey) $s = $question->type == "checkbox" ? $question->slug . $k : $question->slug; $exists = array_key_exists($s, $decodedJson); - if ($exists && $question->type == "radio") + if ($exists && ($question->type == "radio" || $question->type == "select" || $question->type == "sentiment_scale")) return $decodedJson[$s] == $k; return $exists; @@ -241,8 +284,8 @@ public static function generateReportData($survey) }, ARRAY_FILTER_USE_BOTH); }; - // Radio ve checkbox için farklı işlem - if ($question->type == "radio") { + // Radio, select ve checkbox için farklı işlem + if ($question->type == "radio" || $question->type == "select" || $question->type == "sentiment_scale") { // Radio için: Her katılımcıyı bir kez kontrol et ve cevabını bul $allParticipants = $searchAll(); @@ -297,18 +340,21 @@ public static function generateReportData($survey) } } - if ($question->type != "textarea") + $textLike = ["textarea", "short_text", "email", "number", "scale", "url", "phone", "date", "time"]; + if (! in_array($question->type, $textLike, true)) continue; $data = $searchAll(); foreach ($data as $answer) { - $answerValue = json_decode($answer->data, JSON_OBJECT_AS_ARRAY)[$question->slug]; + $decoded = json_decode($answer->data, JSON_OBJECT_AS_ARRAY); + if (! isset($decoded[$question->slug])) + continue; + $answerValue = $decoded[$question->slug]; $generatedData[$group0][$question->type . "::" . $question->title][] = (object) [ "id" => $answer->participantKey ?? $answer->personalId, "fullname" => $answer->fullname, "department" => $answer->department, - #"answer" => $answerTitle, "value" => $answerValue ]; @@ -324,78 +370,71 @@ public static function report($survey) $result = []; - $group0Data = current($generatedData); - if (! $group0Data) - $group0Data = []; + foreach ($generatedData as $groupName => $groupQuestions) { + foreach ($groupQuestions as $key => $question) { + $split = explode("::", $key, 2); - foreach ($group0Data as $key => $question) { - $split = explode("::", $key); + $type = $split[0] ?? "unknown"; + $title = $split[1] ?? $key; + $displayTitle = ($groupName && $groupName !== "default") + ? ($groupName . " / " . $title) + : $title; - $type = $split[0]; - $title = $split[1]; + $result[$displayTitle] = [ + "type" => $type, + "group" => $groupName, + ]; - $result[$title] = [ - "type" => $type - ]; + $result[$displayTitle]["list-json"] = []; - $result[$title]["list-json"] = []; + $totalCount = 0; + if ($type === "radio" || $type === "checkbox" || $type === "select" || $type === "sentiment_scale") { + $uniqueParticipantIds = []; - $totalCount = 0; - if ($type === "radio" || $type === "checkbox") { - // Radio ve Checkbox için benzersiz katılımcı sayısını hesaplamak için - $uniqueParticipantIds = []; - - foreach ($question as $answerK => $answerV) { - $count = count($answerV); - $result[$title]["answers"][$answerK] = $count; - - // Radio ve Checkbox için benzersiz katılımcı ID'lerini topla - foreach ($answerV as $participant) { - // personalId veya id field'ını kontrol et - $participantId = $participant->id ?? $participant->personalId ?? null; - if ($participantId && !in_array($participantId, $uniqueParticipantIds)) { - $uniqueParticipantIds[] = $participantId; + foreach ($question as $answerK => $answerV) { + $count = count($answerV); + $result[$displayTitle]["answers"][$answerK] = $count; + + foreach ($answerV as $participant) { + $participantId = $participant->id ?? $participant->personalId ?? null; + if ($participantId && !in_array($participantId, $uniqueParticipantIds)) { + $uniqueParticipantIds[] = $participantId; + } } } - } - - // Radio ve Checkbox için benzersiz katılımcı sayısını kullan - $totalCount = count($uniqueParticipantIds); - $result[$title]["total"] = $totalCount; - } else { - // Textarea için benzersiz katılımcı sayısını hesaplamak için - $uniqueParticipantIds = []; - $emptyCount = $fillCount = 0; - - foreach ($question as $answerK => $answerV) { - // personalId veya id field'ını kontrol et - $participantId = $answerV->id ?? $answerV->personalId ?? null; - - // Benzersiz katılımcı kontrolü - if ($participantId && !in_array($participantId, $uniqueParticipantIds)) { - $uniqueParticipantIds[] = $participantId; - - if (empty($answerV->value)) - $emptyCount++; - else { - $fillCount++; - $result[$title]["list-json"][] = $answerV; + $totalCount = count($uniqueParticipantIds); + $result[$displayTitle]["total"] = $totalCount; + } else { + $uniqueParticipantIds = []; + $emptyCount = $fillCount = 0; + + foreach ($question as $answerK => $answerV) { + $participantId = $answerV->id ?? $answerV->personalId ?? null; + + if ($participantId && !in_array($participantId, $uniqueParticipantIds)) { + $uniqueParticipantIds[] = $participantId; + + if (empty($answerV->value)) + $emptyCount++; + else { + $fillCount++; + $result[$displayTitle]["list-json"][] = $answerV; + } } } - } - $result[$title]["answers"] = [ - "Dolu" => $fillCount, - "Boş" => $emptyCount - ]; + $result[$displayTitle]["answers"] = [ + lang("survey.report.filled") => $fillCount, + lang("survey.report.empty") => $emptyCount + ]; - $totalCount = count($uniqueParticipantIds); + $totalCount = count($uniqueParticipantIds); + $result[$displayTitle]["list-json"] = data_json($result[$displayTitle]["list-json"]); + } - $result[$title]["list-json"] = data_json($result[$title]["list-json"]); + $result[$displayTitle]["total"] = $totalCount; } - - $result[$title]["total"] = $totalCount; } return $result; diff --git a/app/views/main.php b/app/views/main.php index 2374f39..dba2112 100644 --- a/app/views/main.php +++ b/app/views/main.php @@ -37,11 +37,11 @@ -
-