📄 Source: index.php
<?php
session_start();
require_once 'config.php';
$error = "";
$success = false;
$newQuizId = "";
$masterPassword = "";
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['action']) && $_POST['action'] === 'create') {
$quizTitle = trim($_POST['quiz_title'] ?? 'Quiz fără titlu');
$masterPassword = trim($_POST['master_password'] ?? '');
$questions = [];
$questionTexts = $_POST['question_text'] ?? [];
$questionTypes = $_POST['question_type'] ?? [];
$optionsData = $_POST['options'] ?? [];
$isMultipleCorrect = $_POST['is_multiple_correct'] ?? [];
$singleCorrectAnswers = $_POST['correct_answer_single'] ?? [];
$multipleCorrectAnswers = $_POST['correct_answers_multiple'] ?? [];
for ($i = 0; $i < count($questionTexts); $i++) {
if (!empty($questionTexts[$i])) {
$q = [
'text' => $questionTexts[$i],
'type' => $questionTypes[$i] ?? 'text'
];
if ($q['type'] === 'choice') {
// Filtrăm opțiunile goale
$opts = isset($optionsData[$i]) ? array_values(array_filter($optionsData[$i], function($opt) {
return !empty(trim($opt));
})) : [];
$q['options'] = $opts;
$isMulti = isset($isMultipleCorrect[$i]) && $isMultipleCorrect[$i] == '1';
$q['multiple_correct'] = $isMulti;
if ($isMulti) {
$correctValues = isset($multipleCorrectAnswers[$i]) ? $multipleCorrectAnswers[$i] : [];
if (!is_array($correctValues)) {
$correctValues = explode(',', $correctValues);
}
$q['correct'] = array_values(array_filter($correctValues));
} else {
$q['correct'] = $singleCorrectAnswers[$i] ?? '';
}
} else {
$q['correct'] = $singleCorrectAnswers[$i] ?? '';
}
$questions[] = $q;
}
}
if (count($questions) > 0 && !empty($masterPassword)) {
$newQuizId = generateQuizId();
$quizData = [
'id' => $newQuizId,
'title' => $quizTitle,
'questions' => $questions,
'master_password' => $masterPassword,
'created' => date('Y-m-d H:i:s'),
'submissions' => []
];
saveQuiz($newQuizId, $quizData);
$success = true;
} else {
$error = "Adaugă cel puțin o întrebare și o parolă master.";
}
}
?>
<!DOCTYPE html>
<html lang="ro">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QuizMaster - Creează quiz</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<style>
.option-row {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
background: var(--option-bg);
padding: 0.4rem 0.4rem 0.4rem 1rem;
border-radius: 2rem;
border: 1px solid var(--border-color);
}
.option-row input {
flex: 1;
background: transparent;
border: none;
padding: 0.5rem;
color: var(--input-text);
font-size: 0.9rem;
}
.option-row input:focus {
outline: none;
}
.correct-badge {
cursor: pointer;
padding: 0.25rem 0.7rem;
border-radius: 2rem;
background: var(--input-bg);
border: 1px solid var(--border-color);
font-size: 0.7rem;
white-space: nowrap;
transition: all 0.2s;
}
.correct-badge:hover {
transform: scale(1.05);
}
.correct-badge.selected {
background: var(--success);
color: white;
}
.correct-badge.multi-selected {
background: var(--info);
color: white;
}
.remove-option {
background: var(--btn-danger);
color: white;
border: none;
border-radius: 2rem;
width: 28px;
height: 28px;
cursor: pointer;
font-size: 0.8rem;
}
.selected-display {
font-size: 0.8rem;
color: var(--success);
margin-top: 0.5rem;
padding: 0.3rem;
background: var(--input-bg);
border-radius: 1rem;
}
.question-card {
background: var(--code-bg);
border-radius: 1rem;
padding: 1rem;
margin-bottom: 1rem;
border: 1px solid var(--border-color);
}
</style>
</head>
<body>
<div class="theme-switcher">
<button class="theme-btn" data-theme="light">☀️</button>
<button class="theme-btn" data-theme="dark">🌙</button>
<button class="theme-btn" data-theme="ocean">🌊</button>
<button class="theme-btn" data-theme="sunset">🌅</button>
</div>
<div class="container">
<header class="header">
<h1>🎯 Creează un Quiz</h1>
<p class="subhead">Adaugă întrebări, opțiuni și alege răspunsurile corecte</p>
</header>
<?php if ($success): ?>
<div class="share-card">
<h3>🎉 Quiz creat cu succes!</h3>
<p><strong>🔐 Parolă master:</strong> <?php echo htmlspecialchars($masterPassword); ?></p>
<p>🔗 Link pentru participanți:</p>
<div class="quiz-link">
<?php echo "http://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) . "/solve.php?id=" . $newQuizId; ?>
</div>
<button onclick="copyToClipboard(this.previousElementSibling.innerText)" style="margin-top: 0.5rem; background: white; color: #059669; border: none; padding: 0.3rem 1rem; border-radius: 2rem; cursor: pointer;">📋 Copiază</button>
<p style="margin-top: 0.5rem;"><a href="dashboard.php?id=<?php echo $newQuizId; ?>" style="color: white;">📊 Dashboard</a></p>
</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="error-message">⚠️ <?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<div class="quiz-builder">
<form method="POST" action="" id="quizForm">
<input type="hidden" name="action" value="create">
<div class="input-field">
<label>📌 Titlu quiz</label>
<input type="text" name="quiz_title" placeholder="Ex: Cultura generală, Test Prieteni..." required>
</div>
<div class="input-field">
<label>🔐 Parolă master</label>
<input type="text" name="master_password" placeholder="Alege o parolă pentru a vedea rezultatele" required>
<small style="color: var(--text-secondary);">📌 Păstrează această parolă! Vei avea nevoie de ea pentru dashboard.</small>
</div>
<hr style="margin: 1.5rem 0; border-color: var(--border-color);">
<h3 style="margin-bottom: 1rem;">📝 Întrebări</h3>
<div id="questionsContainer"></div>
<button type="button" class="btn-primary" onclick="addQuestion()" style="margin-top: 1rem; width: 100%;">+ Adaugă întrebare</button>
<button type="submit" class="btn-primary" style="margin-top: 1rem; width: 100%; background: var(--btn-success);">🚀 Creează Quiz</button>
</form>
</div>
<footer class="footer">
<p>✨ Click pe ✓ pentru a marca răspunsul corect | Poți avea întrebări cu unul sau mai multe răspunsuri corecte</p>
</footer>
</div>
<script>
let questionCounter = 0;
let selectedCorrectOptions = {};
function addQuestion() {
const container = document.getElementById('questionsContainer');
const qid = questionCounter;
selectedCorrectOptions[qid] = [];
const card = document.createElement('div');
card.className = 'question-card';
card.setAttribute('data-qid', qid);
card.innerHTML = `
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
<span style="background: var(--info); color: white; padding: 0.2rem 0.8rem; border-radius: 2rem;">Întrebarea ${questionCounter + 1}</span>
<button type="button" class="btn-danger" onclick="removeQuestion(this)" style="padding: 0.2rem 0.8rem;">✖ Șterge</button>
</div>
<div class="input-field">
<input type="text" name="question_text[]" placeholder="Scrie întrebarea aici..." required style="width: 100%;">
</div>
<div class="input-field">
<select name="question_type[]" onchange="toggleQuestionType(this)" style="width: 100%;">
<option value="text">✍️ Răspuns text</option>
<option value="choice">🔘 Alegeri multiple</option>
</select>
</div>
<div class="options-section" style="display: none;">
<label>📋 Opțiuni:</label>
<div id="options-list-${qid}" style="margin: 0.5rem 0;"></div>
<button type="button" class="btn-secondary" onclick="addOption(${qid})" style="margin-top: 0.3rem;">+ Adaugă opțiune</button>
<div style="margin-top: 1rem;">
<label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
<input type="checkbox" onchange="toggleMultipleMode(${qid}, this)">
<span>🔘 Răspuns multiplu corect (poți selecta mai multe opțiuni corecte)</span>
</label>
<div id="multi-hint-${qid}" style="display: none; font-size: 0.7rem; color: var(--text-secondary); margin-top: 0.3rem;">
💡 Click pe opțiunile corecte pentru a le selecta pe toate
</div>
</div>
</div>
<div class="single-answer-field" style="margin-top: 1rem;">
<label>✅ Răspuns corect</label>
<input type="text" name="correct_answer_single[]" placeholder="Care e răspunsul corect?" style="width: 100%; padding: 0.8rem; border-radius: 1rem; border: 2px solid var(--input-border); background: var(--input-bg); color: var(--input-text);">
</div>
<div class="multiple-answer-field" style="display: none; margin-top: 1rem;">
<label>✅ Răspunsuri corecte selectate:</label>
<input type="hidden" name="correct_answers_multiple[${qid}][]" id="correct-multiple-${qid}">
<div id="selected-display-${qid}" class="selected-display">📌 Niciun răspuns corect selectat</div>
</div>
<input type="hidden" name="is_multiple_correct[${qid}]" id="is-multiple-${qid}" value="0">
`;
container.appendChild(card);
// Adaugă 2 opțiuni implicite
for (let i = 0; i < 2; i++) {
addOption(qid);
}
questionCounter++;
}
function removeQuestion(btn) {
const card = btn.closest('.question-card');
if (document.querySelectorAll('.question-card').length > 1) {
const qid = card.getAttribute('data-qid');
delete selectedCorrectOptions[qid];
card.remove();
// Re-numărăm
document.querySelectorAll('.question-card').forEach((card, idx) => {
const header = card.querySelector('span');
if (header && header.textContent.includes('Întrebarea')) {
header.textContent = `Întrebarea ${idx + 1}`;
}
card.setAttribute('data-qid', idx);
});
} else {
alert("Trebuie să ai cel puțin o întrebare!");
}
}
function toggleQuestionType(select) {
const card = select.closest('.question-card');
const optionsSection = card.querySelector('.options-section');
const singleField = card.querySelector('.single-answer-field');
const multipleField = card.querySelector('.multiple-answer-field');
if (select.value === 'choice') {
optionsSection.style.display = 'block';
singleField.style.display = 'none';
multipleField.style.display = 'none';
} else {
optionsSection.style.display = 'none';
singleField.style.display = 'block';
multipleField.style.display = 'none';
}
}
function addOption(qid) {
const container = document.getElementById(`options-list-${qid}`);
if (!container) return;
const optIndex = container.children.length;
const optionDiv = document.createElement('div');
optionDiv.className = 'option-row';
optionDiv.innerHTML = `
<input type="text" name="options[${qid}][]" placeholder="Opțiunea ${optIndex + 1}">
<span class="correct-badge" onclick="toggleCorrectOption(${qid}, this)">✓</span>
<button type="button" class="remove-option" onclick="this.closest('.option-row').remove()">✖</button>
`;
container.appendChild(optionDiv);
}
function toggleMultipleMode(qid, checkbox) {
const isMultiple = checkbox.checked;
const hiddenInput = document.getElementById(`is-multiple-${qid}`);
const multipleField = document.querySelector(`.question-card[data-qid="${qid}"] .multiple-answer-field`);
const singleField = document.querySelector(`.question-card[data-qid="${qid}"] .single-answer-field`);
const hint = document.getElementById(`multi-hint-${qid}`);
hiddenInput.value = isMultiple ? '1' : '0';
if (isMultiple) {
multipleField.style.display = 'block';
singleField.style.display = 'none';
if (hint) hint.style.display = 'block';
// Resetează selecțiile
const badges = document.querySelectorAll(`.question-card[data-qid="${qid}"] .correct-badge`);
badges.forEach(badge => {
badge.classList.remove('selected', 'multi-selected');
badge.textContent = '✓';
});
selectedCorrectOptions[qid] = [];
updateSelectedDisplay(qid);
} else {
multipleField.style.display = 'none';
singleField.style.display = 'block';
if (hint) hint.style.display = 'none';
// Resetează badge-urile
const badges = document.querySelectorAll(`.question-card[data-qid="${qid}"] .correct-badge`);
badges.forEach(badge => {
badge.classList.remove('selected', 'multi-selected');
badge.textContent = '✓';
});
}
}
function toggleCorrectOption(qid, element) {
const card = document.querySelector(`.question-card[data-qid="${qid}"]`);
const isMultipleCheckbox = card.querySelector('input[type="checkbox"]');
const isMultiple = isMultipleCheckbox && isMultipleCheckbox.checked;
const optionInput = element.closest('.option-row').querySelector('input');
const optionText = optionInput.value;
if (!optionText.trim()) {
alert('Completează mai întâi textul opțiunii!');
return;
}
if (isMultiple) {
// Mod multiplu
if (element.classList.contains('multi-selected')) {
element.classList.remove('multi-selected');
element.textContent = '✓';
selectedCorrectOptions[qid] = selectedCorrectOptions[qid].filter(opt => opt !== optionText);
} else {
element.classList.add('multi-selected');
element.textContent = '✓✓';
if (!selectedCorrectOptions[qid].includes(optionText)) {
selectedCorrectOptions[qid].push(optionText);
}
}
updateSelectedDisplay(qid);
// Actualizează hidden input
const hiddenInput = document.getElementById(`correct-multiple-${qid}`);
if (hiddenInput) {
hiddenInput.value = selectedCorrectOptions[qid].join(',');
}
} else {
// Mod single
const allBadges = card.querySelectorAll('.correct-badge');
allBadges.forEach(badge => {
badge.classList.remove('selected');
badge.textContent = '✓';
});
element.classList.add('selected');
element.textContent = '✓ SELECTAT';
// Actualizează câmpul single answer
const singleInput = card.querySelector('input[name="correct_answer_single[]"]');
if (singleInput) {
singleInput.value = optionText;
}
}
}
function updateSelectedDisplay(qid) {
const displayDiv = document.getElementById(`selected-display-${qid}`);
if (displayDiv) {
if (selectedCorrectOptions[qid] && selectedCorrectOptions[qid].length > 0) {
displayDiv.innerHTML = `📌 Selectate: ${selectedCorrectOptions[qid].join(', ')}`;
displayDiv.style.color = 'var(--success)';
} else {
displayDiv.innerHTML = '📌 Niciun răspuns corect selectat';
displayDiv.style.color = 'var(--text-secondary)';
}
}
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text);
alert('Link copiat!');
}
// Inițializare - prima întrebare
addQuestion();
// Teme
(function() {
const savedTheme = localStorage.getItem('quiz-theme');
if (savedTheme) document.documentElement.setAttribute('data-theme', savedTheme);
else document.documentElement.setAttribute('data-theme', 'light');
document.querySelectorAll('.theme-btn').forEach(btn => {
btn.addEventListener('click', function() {
const theme = this.getAttribute('data-theme');
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('quiz-theme', theme);
});
});
})();
</script>
</body>
</html>
← Back