Added Required button, Text box question type, Added sweetalerts
This commit is contained in:
parent
7ad8d86e7f
commit
22bf15864e
|
@ -25,6 +25,15 @@ class FormController extends Controller
|
||||||
return view('forms.create');
|
return view('forms.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function togglePublish(Form $form)
|
||||||
|
{
|
||||||
|
$form->is_published = !$form->is_published;
|
||||||
|
$form->save();
|
||||||
|
|
||||||
|
return redirect()->route('forms.show', $form->id)->with('success', 'Form publish status updated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function edit(Form $form)
|
public function edit(Form $form)
|
||||||
{
|
{
|
||||||
// Questions are already fetched with their options cast to array due to the casts property
|
// Questions are already fetched with their options cast to array due to the casts property
|
||||||
|
@ -41,19 +50,21 @@ class FormController extends Controller
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'title' => 'required|string|max:255',
|
'title' => 'required|string|max:255',
|
||||||
'description' => 'nullable|string',
|
'description' => 'nullable|string',
|
||||||
'questions' => 'required|array',
|
'questions' => 'required|array',
|
||||||
'questions.*.type' => 'required|string|in:multiple_choice,checkbox,dropdown,short_answer,long_answer',
|
'questions.*.type' => 'required|string|in:multiple_choice,checkbox,dropdown,text',
|
||||||
'questions.*.text' => 'required|string', // This should match the key used in the JavaScript
|
'questions.*.text' => 'required|string',
|
||||||
'questions.*.options' => 'nullable|array',
|
'questions.*.options' => 'nullable|array',
|
||||||
|
'questions.*.required' => 'nullable|boolean',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$form = new Form();
|
$form = new Form();
|
||||||
$form->title = $validatedData['title'];
|
$form->title = $validatedData['title'];
|
||||||
$form->description = $validatedData['description'];
|
$form->description = $validatedData['description'];
|
||||||
$form->is_published = $request->input('is_published', false); // Default to false if not provided
|
$form->is_published = $request->input('is_published', false);
|
||||||
$form->user_id = Auth::id();
|
$form->user_id = Auth::id();
|
||||||
$form->save();
|
$form->save();
|
||||||
|
|
||||||
|
@ -61,15 +72,18 @@ class FormController extends Controller
|
||||||
$question = new Question();
|
$question = new Question();
|
||||||
$question->form_id = $form->id;
|
$question->form_id = $form->id;
|
||||||
$question->type = $questionData['type'];
|
$question->type = $questionData['type'];
|
||||||
$question->question_text = $questionData['text']; // Ensure this matches the key in the validated data
|
$question->question_text = $questionData['text'];
|
||||||
$question->options = isset($questionData['options']) ? json_encode($questionData['options']) : null;
|
$question->options = isset($questionData['options']) ? json_encode($questionData['options']) : null;
|
||||||
|
$question->required = isset($questionData['required']) ? $questionData['required'] : false;
|
||||||
$question->save();
|
$question->save();
|
||||||
}
|
}
|
||||||
Session::flash('success', 'Form created successfully!');
|
|
||||||
return response()->json(['success' => true, 'form_id' => $form->id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return response()->json(['success' => true, 'form_id' => $form->id]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error saving form: ' . $e->getMessage(), ['exception' => $e]);
|
||||||
|
return response()->json(['success' => false, 'message' => 'Error saving form'], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function show(Form $form)
|
public function show(Form $form)
|
||||||
{
|
{
|
||||||
|
@ -99,7 +113,7 @@ class FormController extends Controller
|
||||||
'description' => 'nullable|string|max:255',
|
'description' => 'nullable|string|max:255',
|
||||||
'questions' => 'required|array',
|
'questions' => 'required|array',
|
||||||
'questions.*.id' => 'nullable|exists:questions,id',
|
'questions.*.id' => 'nullable|exists:questions,id',
|
||||||
'questions.*.type' => 'required|string|in:multiple_choice,checkbox,dropdown,short_answer,long_answer',
|
'questions.*.type' => 'required|string|in:multiple_choice,checkbox,dropdown,text',
|
||||||
'questions.*.text' => 'required|string|max:255',
|
'questions.*.text' => 'required|string|max:255',
|
||||||
'questions.*.options' => 'nullable|array',
|
'questions.*.options' => 'nullable|array',
|
||||||
'questions.*.options.*' => 'nullable|string|max:255',
|
'questions.*.options.*' => 'nullable|string|max:255',
|
||||||
|
@ -149,6 +163,8 @@ class FormController extends Controller
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function destroy(Form $form)
|
public function destroy(Form $form)
|
||||||
{
|
{
|
||||||
// This will also delete all related questions and responses due to foreign key constraints
|
// This will also delete all related questions and responses due to foreign key constraints
|
||||||
|
|
|
@ -103,12 +103,27 @@ public function viewResponses(Form $form)
|
||||||
{
|
{
|
||||||
Log::info($request->all()); // Log the entire request data for debugging
|
Log::info($request->all()); // Log the entire request data for debugging
|
||||||
|
|
||||||
|
// Fetch all questions for the form
|
||||||
|
$questions = $form->questions;
|
||||||
|
|
||||||
|
// Extract IDs of required questions
|
||||||
|
$requiredQuestionIds = $questions->where('required', true)->pluck('id')->toArray();
|
||||||
|
|
||||||
// Validate and process form submission
|
// Validate and process form submission
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'answers' => 'required|array',
|
'answers' => 'required|array',
|
||||||
'answers.*' => 'required',
|
'answers.*' => 'required', // Ensure all answers are provided
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Ensure all required questions are answered
|
||||||
|
foreach ($requiredQuestionIds as $requiredQuestionId) {
|
||||||
|
if (!array_key_exists($requiredQuestionId, $validatedData['answers'])) {
|
||||||
|
return redirect()->back()
|
||||||
|
->withErrors(['errors' => 'Please answer all required questions.'])
|
||||||
|
->withInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log::info($validatedData); // Log the validated data for debugging
|
Log::info($validatedData); // Log the validated data for debugging
|
||||||
|
|
||||||
// Generate a UUID for response_id
|
// Generate a UUID for response_id
|
||||||
|
@ -129,4 +144,9 @@ public function viewResponses(Form $form)
|
||||||
return redirect()->route('responses.showForm', $form)
|
return redirect()->route('responses.showForm', $form)
|
||||||
->with('success', 'Response submitted successfully.');
|
->with('success', 'Response submitted successfully.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,9 @@ return new class extends Migration
|
||||||
Schema::create('questions', function (Blueprint $table) {
|
Schema::create('questions', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignId('form_id')->constrained()->onDelete('cascade');
|
$table->foreignId('form_id')->constrained()->onDelete('cascade');
|
||||||
$table->enum('type', ['multiple_choice', 'checkbox', 'dropdown', 'short_answer', 'long_answer']);
|
$table->enum('type', ['multiple_choice', 'checkbox', 'dropdown', 'text']);
|
||||||
$table->text('question_text');
|
$table->text('question_text');
|
||||||
|
$table->boolean('required')->default(false);
|
||||||
$table->json('options')->nullable(); // Store options as JSON if applicable
|
$table->json('options')->nullable(); // Store options as JSON if applicable
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,216 +1,3 @@
|
||||||
// document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
// const questionsSection = document.getElementById("questions_section");
|
|
||||||
|
|
||||||
// function addOption(button) {
|
|
||||||
// const optionContainer = button.previousElementSibling;
|
|
||||||
// const optionDiv = document.createElement("div");
|
|
||||||
// optionDiv.className = "option";
|
|
||||||
// optionDiv.innerHTML = `
|
|
||||||
// <input type="text" class="form-control option-input" placeholder="New Option" />
|
|
||||||
// <span class="delete-option" onclick="deleteOption(this)">✕</span>
|
|
||||||
// `;
|
|
||||||
// optionContainer.appendChild(optionDiv);
|
|
||||||
// updateAddButtonPosition();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function deleteOption(span) {
|
|
||||||
// const optionDiv = span.parentElement;
|
|
||||||
// optionDiv.remove();
|
|
||||||
// updateAddButtonPosition();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function changeQuestionType(select) {
|
|
||||||
// const questionInput = select.nextElementSibling;
|
|
||||||
// questionInput.style.display = "block";
|
|
||||||
// const optionsContainer = select.nextElementSibling.nextElementSibling;
|
|
||||||
// optionsContainer.innerHTML =
|
|
||||||
// '<input type="text" class="form-control option-input" placeholder="Option 1">';
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let questionCount = document.querySelectorAll(".question").length;
|
|
||||||
|
|
||||||
// function addNewQuestion() {
|
|
||||||
// const newQuestionDiv = document.createElement("div");
|
|
||||||
// newQuestionDiv.className = "question";
|
|
||||||
// newQuestionDiv.innerHTML = `
|
|
||||||
// <select class="form-control question_type" onchange="changeQuestionType(this)">
|
|
||||||
// <option value="">Select Question Type</option>
|
|
||||||
// <option value="multiple_choice">Multiple Choice</option>
|
|
||||||
// <option value="checkbox">Checkbox</option>
|
|
||||||
// <option value="dropdown">Dropdown</option>
|
|
||||||
// </select>
|
|
||||||
// <input type="text" class="form-control question-input" placeholder="Type your question here" />
|
|
||||||
// <div class="options-container">
|
|
||||||
// <div class="option">
|
|
||||||
// <input type="text" class="form-control option-input" placeholder="Option 1" />
|
|
||||||
// <span class="delete-option" onclick="deleteOption(this)">✕</span>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// <button class="btn btn-secondary" onclick="addOption(this)">Add Option</button>
|
|
||||||
// <button class="btnn" onclick="deleteQuestion(this)">
|
|
||||||
// <img src="public/images/bin.png" alt="" width="20px" height="20px" />
|
|
||||||
// </button>
|
|
||||||
// `;
|
|
||||||
// questionsSection.appendChild(newQuestionDiv);
|
|
||||||
// questionCount++;
|
|
||||||
// updateAddButtonPosition();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function saveForm() {
|
|
||||||
// const formTitle = document.getElementById("form-title").value;
|
|
||||||
// const formDescription =
|
|
||||||
// document.getElementById("form-description").value;
|
|
||||||
// const questions = document.querySelectorAll(".question");
|
|
||||||
// let formData = [];
|
|
||||||
|
|
||||||
// questions.forEach((question, index) => {
|
|
||||||
// const questionType = question.querySelector("select").value;
|
|
||||||
// const questionText =
|
|
||||||
// question.querySelector(".question-input").value;
|
|
||||||
// const options = Array.from(
|
|
||||||
// question.querySelectorAll(".option-input")
|
|
||||||
// ).map((input) => input.value);
|
|
||||||
// formData.push({
|
|
||||||
// type: questionType,
|
|
||||||
// text: questionText, // Ensure this matches the key in the PHP validation
|
|
||||||
// options: options,
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Get CSRF token
|
|
||||||
// const csrfTokenMeta = document.querySelector('meta[name="csrf-token"]');
|
|
||||||
// let csrfToken = "";
|
|
||||||
// if (csrfTokenMeta) {
|
|
||||||
// csrfToken = csrfTokenMeta.getAttribute("content");
|
|
||||||
// } else {
|
|
||||||
// console.error("CSRF token meta tag not found.");
|
|
||||||
// // Handle the error condition gracefully or abort further execution
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const data = {
|
|
||||||
// title: formTitle,
|
|
||||||
// description: formDescription,
|
|
||||||
// questions: formData,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// console.log("Form Data:", data); // Log form data
|
|
||||||
// console.log("CSRF Token:", csrfToken); // Log CSRF token
|
|
||||||
|
|
||||||
// // Send AJAX request to save the form data
|
|
||||||
// fetch("/forms", {
|
|
||||||
// method: "POST",
|
|
||||||
// headers: {
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// "X-CSRF-TOKEN": csrfToken,
|
|
||||||
// },
|
|
||||||
// body: JSON.stringify(data),
|
|
||||||
// })
|
|
||||||
// .then((response) => {
|
|
||||||
// if (!response.ok) {
|
|
||||||
// throw new Error("Network response was not ok");
|
|
||||||
// }
|
|
||||||
// return response.json();
|
|
||||||
// })
|
|
||||||
// .then((result) => {
|
|
||||||
// console.log("Server Response:", result); // Log server response
|
|
||||||
// if (result.success) {
|
|
||||||
// alert("Form saved successfully!");
|
|
||||||
// window.location.href = "/forms"; // Redirect to forms index page
|
|
||||||
// } else {
|
|
||||||
// alert("Failed to save form.");
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .catch((error) => {
|
|
||||||
// console.error("Error saving form:", error);
|
|
||||||
// alert("An error occurred while saving the form.");
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// window.addNewQuestion = addNewQuestion;
|
|
||||||
// window.deleteQuestion = deleteQuestion;
|
|
||||||
// window.addOption = addOption;
|
|
||||||
// window.changeQuestionType = changeQuestionType;
|
|
||||||
// window.saveForm = saveForm;
|
|
||||||
|
|
||||||
// window.previewForm = function (formId) {
|
|
||||||
// const formTitle = document.getElementById("form-title").value;
|
|
||||||
// const formDescription =
|
|
||||||
// document.getElementById("form-description").value;
|
|
||||||
// const questions = document.querySelectorAll(".question");
|
|
||||||
// let formData = [];
|
|
||||||
|
|
||||||
// questions.forEach((question, index) => {
|
|
||||||
// const questionType = question.querySelector("select").value;
|
|
||||||
// const questionText =
|
|
||||||
// question.querySelector(".question-input").value;
|
|
||||||
// const options = Array.from(
|
|
||||||
// question.querySelectorAll(".option-input")
|
|
||||||
// ).map((input) => input.value);
|
|
||||||
// formData.push({
|
|
||||||
// type: questionType,
|
|
||||||
// text: questionText,
|
|
||||||
// options: options,
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const formParams = new URLSearchParams({
|
|
||||||
// title: formTitle,
|
|
||||||
// description: formDescription,
|
|
||||||
// data: JSON.stringify(formData),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// window.location.href = '/forms/' + formId + '/preview';
|
|
||||||
// };
|
|
||||||
|
|
||||||
// window.addNewQuestion = addNewQuestion;
|
|
||||||
// window.deleteQuestion = deleteQuestion;
|
|
||||||
// window.addOption = addOption;
|
|
||||||
// window.changeQuestionType = changeQuestionType;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// function deleteQuestion(element) {
|
|
||||||
// let questionContainer = element.closest(".question");
|
|
||||||
// if (questionContainer) {
|
|
||||||
// questionContainer.remove();
|
|
||||||
// updateAddButtonPosition();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function deleteOption(span) {
|
|
||||||
// const optionDiv = span.parentElement;
|
|
||||||
// optionDiv.remove();
|
|
||||||
// updateAddButtonPosition();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function updateAddButtonPosition() {
|
|
||||||
// const questionsSection = document.getElementById("questions_section");
|
|
||||||
// const lastQuestion = questionsSection.lastElementChild;
|
|
||||||
|
|
||||||
// // Check if lastQuestion exists before accessing its properties
|
|
||||||
// if (lastQuestion) {
|
|
||||||
// const selectQuestionType = lastQuestion.querySelector(".question_type");
|
|
||||||
|
|
||||||
// // Ensure selectQuestionType is not null before accessing offsetTop
|
|
||||||
// if (selectQuestionType) {
|
|
||||||
// const sidebar = document.getElementById("moveableDiv");
|
|
||||||
// const offset = selectQuestionType.offsetTop - sidebar.offsetHeight;
|
|
||||||
// sidebar.style.transform = `translateY(${offset}px)`;
|
|
||||||
// console.log(`Moving sidebar to: ${offset}px`);
|
|
||||||
// } else {
|
|
||||||
// console.warn("No .question_type found in last question.");
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// const sidebar = document.getElementById("moveableDiv");
|
|
||||||
// sidebar.style.transform = `translateY(0px)`;
|
|
||||||
// console.log(`Moving sidebar to: 0px`);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const questionsSection = document.getElementById("questions_section");
|
const questionsSection = document.getElementById("questions_section");
|
||||||
|
|
||||||
|
@ -233,12 +20,27 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
updateAddButtonPosition();
|
updateAddButtonPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeQuestionType(select) {
|
function changeQuestionType(selectElement) {
|
||||||
const questionInput = select.nextElementSibling;
|
const questionContainer = selectElement.closest('.question');
|
||||||
questionInput.style.display = "block";
|
const optionsContainer = questionContainer.querySelector('.options-container');
|
||||||
const optionsContainer = select.nextElementSibling.nextElementSibling;
|
const addOptionButton = questionContainer.querySelector('.btn-secondary');
|
||||||
optionsContainer.innerHTML =
|
const questionType = selectElement.value;
|
||||||
'<input type="text" class="form-control option-input" placeholder="Option 1">';
|
|
||||||
|
// Clear the options container
|
||||||
|
optionsContainer.innerHTML = '';
|
||||||
|
|
||||||
|
if (questionType === 'multiple_choice' || questionType === 'checkbox' || questionType === 'dropdown') {
|
||||||
|
const optionDiv = document.createElement('div');
|
||||||
|
optionDiv.className = 'option d-flex align-items-center mb-2';
|
||||||
|
optionDiv.innerHTML = `
|
||||||
|
<input type="text" name="option" class="form-control option-input" placeholder="Option 1" />
|
||||||
|
<span class="delete-option ml-2 text-danger" onclick="deleteOption(this)" style="cursor: pointer;">✕</span>
|
||||||
|
`;
|
||||||
|
optionsContainer.appendChild(optionDiv);
|
||||||
|
addOptionButton.style.display = 'inline-block'; // Show the "Add Option" button
|
||||||
|
} else if (questionType === 'text') {
|
||||||
|
addOptionButton.style.display = 'none'; // Hide the "Add Option" button
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let questionCount = document.querySelectorAll(".question").length;
|
let questionCount = document.querySelectorAll(".question").length;
|
||||||
|
@ -247,26 +49,27 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
const newQuestionDiv = document.createElement("div");
|
const newQuestionDiv = document.createElement("div");
|
||||||
newQuestionDiv.className = "question";
|
newQuestionDiv.className = "question";
|
||||||
newQuestionDiv.innerHTML = `
|
newQuestionDiv.innerHTML = `
|
||||||
<div class="question mb-4 p-3 border rounded bg-white">
|
<div class="question mb-4 p-4 border rounded bg-white">
|
||||||
<select class="form-control question_type mb-1" onchange="changeQuestionType(this)">
|
<select class="form-control question_type mb-1" onchange="changeQuestionType(this)">
|
||||||
<option value="">Select Question Type</option>
|
<option value="">Select Question Type</option>
|
||||||
<option value="multiple_choice">Multiple Choice</option>
|
<option value="multiple_choice">Multiple Choice</option>
|
||||||
<option value="checkbox">Checkbox</option>
|
<option value="checkbox">Checkbox</option>
|
||||||
<option value="dropdown">Dropdown</option>
|
<option value="dropdown">Dropdown</option>
|
||||||
|
<option value="text">Text</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="text" name="question" class="form-control question-input mb-3" placeholder="Type your question here" />
|
<input type="text" name="question" class="form-control question-input mb-3" placeholder="Type your question here" />
|
||||||
<div class="options-container mb-3">
|
<div class="options-container mb-3">
|
||||||
<div class="option d-flex align-items-center">
|
<!-- Options or text input will be dynamically added here -->
|
||||||
<input type="text" name="option" class="form-control option-input" placeholder="Option 1" />
|
|
||||||
<span class="delete-option ml-2 text-danger" onclick="deleteOption(this)" style="cursor: pointer;">✕</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<button class="btn btn-secondary add-option-btn" onclick="addOption(this)">
|
||||||
<button class="btn btn-secondary" onclick="addOption(this)">
|
|
||||||
Add Option
|
Add Option
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
||||||
<img src="/images/bin.png" alt="" width="20px" height="20px" />
|
<img src="/images/bin.png" alt="" width="20px" height="20px" />
|
||||||
</button>
|
</button>
|
||||||
|
<label class="ml-3">
|
||||||
|
<input type="checkbox" class="required-checkbox"> Required
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
questionsSection.appendChild(newQuestionDiv);
|
questionsSection.appendChild(newQuestionDiv);
|
||||||
|
@ -316,14 +119,21 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
const questions = document.querySelectorAll(".question");
|
const questions = document.querySelectorAll(".question");
|
||||||
let formData = [];
|
let formData = [];
|
||||||
|
|
||||||
questions.forEach((question, index) => {
|
questions.forEach((question) => {
|
||||||
const questionType = question.querySelector("select").value;
|
const questionType = question.querySelector("select").value;
|
||||||
const questionText = question.querySelector(".question-input").value;
|
const questionText = question.querySelector(".question-input").value;
|
||||||
const options = Array.from(question.querySelectorAll(".option-input")).map((input) => input.value);
|
const isRequired = question.querySelector(".required-checkbox").checked;
|
||||||
|
let options = [];
|
||||||
|
|
||||||
|
if (questionType === 'multiple_choice' || questionType === 'checkbox' || questionType === 'dropdown') {
|
||||||
|
options = Array.from(question.querySelectorAll(".option-input")).map((input) => input.value);
|
||||||
|
}
|
||||||
|
|
||||||
formData.push({
|
formData.push({
|
||||||
type: questionType,
|
type: questionType,
|
||||||
text: questionText,
|
text: questionText,
|
||||||
options: options,
|
options: options,
|
||||||
|
required: isRequired
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -339,33 +149,38 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
const data = {
|
const data = {
|
||||||
title: formTitle,
|
title: formTitle,
|
||||||
description: formDescription,
|
description: formDescription,
|
||||||
questions: formData,
|
questions: formData
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("Form Data:", data);
|
|
||||||
console.log("CSRF Token:", csrfToken);
|
|
||||||
|
|
||||||
fetch("/forms", {
|
fetch("/forms", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-CSRF-TOKEN": csrfToken,
|
"X-CSRF-TOKEN": csrfToken
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => response.json())
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error("Network response was not ok");
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
console.log("Server Response:", result);
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
alert("Form saved successfully!");
|
Swal.fire({
|
||||||
|
title: 'Success!',
|
||||||
|
text: 'Form saved successfully.',
|
||||||
|
icon: 'success',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
window.location.href = "/forms";
|
window.location.href = "/forms";
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
alert("Failed to save form.");
|
Swal.fire({
|
||||||
|
title: 'Error!',
|
||||||
|
text: 'Failed to save form.',
|
||||||
|
icon: 'error',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -374,6 +189,12 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
window.addNewQuestion = addNewQuestion;
|
window.addNewQuestion = addNewQuestion;
|
||||||
window.deleteQuestion = deleteQuestion;
|
window.deleteQuestion = deleteQuestion;
|
||||||
window.addOption = addOption;
|
window.addOption = addOption;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
{{-- <!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
@ -98,4 +98,121 @@
|
||||||
<script src={{ asset('js/script.js') }}></script>
|
<script src={{ asset('js/script.js') }}></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
</html> --}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
<title>Google-Form-Clone</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||||
|
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href={{ asset('css/app.css') }} />
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/alpinejs@2.8.2/dist/alpine.min.js" defer></script>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap"
|
||||||
|
rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="background-color: #f4f4f9;" >
|
||||||
|
<nav class="bg-white p-4 shadow-sm">
|
||||||
|
<div class="mx-auto flex justify-between items-center">
|
||||||
|
<a href="{{ url('/') }}" style="color: rgb(103,58,183)"
|
||||||
|
class="text-3xl font-bold font-sans">LaraForms</a>
|
||||||
|
<div class="relative dropdown">
|
||||||
|
<button id="profileMenuButton" class="flex items-center focus:outline-none">
|
||||||
|
<img src="{{ asset('images/user.png') }}" alt="Profile"
|
||||||
|
class="w-10 h-10 rounded-full border-2 border-white">
|
||||||
|
</button>
|
||||||
|
<div id="profileMenu"
|
||||||
|
class="dropdown-menu hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-2">
|
||||||
|
<form method="POST" action="{{ route('logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="block px-4 py-2 text-gray-700 hover:bg-gray-200 w-full text-left">
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<br><br>
|
||||||
|
<div style="background-color: #f4f4f9; max-width: 100%" class="question_form p-4 rounded">
|
||||||
|
<div class="section">
|
||||||
|
<div class="question_title_section mb-1">
|
||||||
|
<div class="question_form_top">
|
||||||
|
<input type="text" id="form-title" name="title" class="form-control form-control-lg p-2 mb-2" placeholder="Untitled Form" />
|
||||||
|
<input type="text" name="description" id="form-description" class="form-control form-control-sm" placeholder="Form Description" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="questions_section">
|
||||||
|
<div class="question mb-4 p-4 border rounded bg-white">
|
||||||
|
<select class="form-control question_type mb-1" onchange="changeQuestionType(this)">
|
||||||
|
<option value="">Select Question Type</option>
|
||||||
|
<option value="multiple_choice">Multiple Choice</option>
|
||||||
|
<option value="checkbox">Checkbox</option>
|
||||||
|
<option value="dropdown">Dropdown</option>
|
||||||
|
<option value="text">Text</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" name="question" class="form-control question-input mb-3" placeholder="Type your question here" />
|
||||||
|
<div class="options-container mb-3">
|
||||||
|
<!-- Options or text input will be dynamically added here -->
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-secondary add-option-btn" onclick="addOption(this)">
|
||||||
|
Add Option
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
||||||
|
<img src="{{ asset('images/bin.png') }}" alt="" width="20px" height="20px" />
|
||||||
|
</button>
|
||||||
|
<label class="ml-3">
|
||||||
|
<input type="checkbox" class="required-checkbox"> Required
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar">
|
||||||
|
<div id="moveableDiv">
|
||||||
|
<button class="btn btn-light shadow-sm" onclick="addNewQuestion();">
|
||||||
|
<img src="{{ asset('images/add.png') }}" alt="" width="20px" height="20px" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="background-color: #f4f4f9;" class="btnsub">
|
||||||
|
<span>
|
||||||
|
<button type="submit" name="save" value="save" onclick="saveForm()"
|
||||||
|
class="btnsave btn btn-secondary">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<button type="submit" name="publish" value="publish" onclick="saveForm()"
|
||||||
|
class="btnsave btn btn-secondary">
|
||||||
|
Publish
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script src={{ asset('js/script.js') }}></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/alpinejs@2.8.2/dist/alpine.min.js" defer></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -60,15 +60,11 @@
|
||||||
@foreach ($questions as $index => $question)
|
@foreach ($questions as $index => $question)
|
||||||
<div class="question mb-4 p-3 border rounded bg-light" data-index="{{ $index }}">
|
<div class="question mb-4 p-3 border rounded bg-light" data-index="{{ $index }}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<select class="form-control question-type" id="question-type-{{ $index }}"
|
<select class="form-control question-type" id="question-type-{{ $index }}" name="questions[{{ $index }}][type]">
|
||||||
name="questions[{{ $index }}][type]">
|
<option value="multiple_choice" {{ $question->type === 'multiple_choice' ? 'selected' : '' }}>Multiple Choice</option>
|
||||||
<option value="multiple_choice"
|
<option value="checkbox" {{ $question->type === 'checkbox' ? 'selected' : '' }}>Checkbox</option>
|
||||||
{{ $question->type === 'multiple_choice' ? 'selected' : '' }}>Multiple Choice
|
<option value="dropdown" {{ $question->type === 'dropdown' ? 'selected' : '' }}>Dropdown</option>
|
||||||
</option>
|
<option value="text" {{ $question->type === 'text' ? 'selected' : '' }}>Text</option>
|
||||||
<option value="checkbox" {{ $question->type === 'checkbox' ? 'selected' : '' }}>
|
|
||||||
Checkbox</option>
|
|
||||||
<option value="dropdown" {{ $question->type === 'dropdown' ? 'selected' : '' }}>
|
|
||||||
Dropdown</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -76,24 +72,25 @@
|
||||||
name="questions[{{ $index }}][text]" class="form-control question-input"
|
name="questions[{{ $index }}][text]" class="form-control question-input"
|
||||||
value="{{ $question->question_text }}" required>
|
value="{{ $question->question_text }}" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group options-container">
|
<div class="form-group form-check">
|
||||||
|
<input type="checkbox" id="question-required-{{ $index }}"
|
||||||
|
name="questions[{{ $index }}][required]" class="form-check-input"
|
||||||
|
{{ $question->required ? 'checked' : '' }}>
|
||||||
|
<label for="question-required-{{ $index }}" class="form-check-label">Required</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group options-container" style="{{ $question->type === 'text' ? 'display:none;' : '' }}">
|
||||||
<label>Options</label>
|
<label>Options</label>
|
||||||
@if (is_array($question->options))
|
@if (is_array($question->options))
|
||||||
@foreach ($question->options as $optionIndex => $option)
|
@foreach ($question->options as $optionIndex => $option)
|
||||||
<div class="option d-flex align-items-center mb-2">
|
<div class="option d-flex align-items-center mb-2">
|
||||||
<input type="text"
|
<input type="text" name="questions[{{ $index }}][options][{{ $optionIndex }}]" class="form-control option-input" value="{{ $option }}">
|
||||||
name="questions[{{ $index }}][options][{{ $optionIndex }}]"
|
<span class="delete-option ml-2 text-danger" onclick="deleteOption(this)" style="cursor: pointer;">✕</span>
|
||||||
class="form-control option-input" value="{{ $option }}">
|
|
||||||
<span class="delete-option ml-2 text-danger" onclick="deleteOption(this)"
|
|
||||||
style="cursor: pointer;">✕</span>
|
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
<button type="button" class="btn btn-secondary" onclick="addOption(this)">Add
|
<button type="button" class="btn btn-secondary" onclick="addOption(this)">Add Option</button>
|
||||||
Option</button>
|
|
||||||
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
||||||
<img src="{{ asset('images/bin.png') }}" alt="" width="20px"
|
<img src="{{ asset('images/bin.png') }}" alt="" width="20px" height="20px" />
|
||||||
height="20px" />
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -106,7 +103,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-primary mb-4" onclick="addNewQuestion()">Add New Question</button>
|
|
||||||
<button type="submit" class="btn btn-success mb-4">Save</button>
|
<button type="submit" class="btn btn-success mb-4">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -142,23 +138,30 @@
|
||||||
const questionHtml = `
|
const questionHtml = `
|
||||||
<div class="question mb-4 p-3 border rounded bg-light" data-index="${questionIndex}">
|
<div class="question mb-4 p-3 border rounded bg-light" data-index="${questionIndex}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<select class="form-control question-type" id="question-type-${questionIndex}" name="questions[${questionIndex}][type]">
|
<select class="form-control question-type" id="question-type-${questionIndex}" name="questions[${questionIndex}][type]" onchange="handleQuestionTypeChange(this)">
|
||||||
<option value="multiple_choice">Multiple Choice</option>
|
<option value="multiple_choice">Multiple Choice</option>
|
||||||
<option value="checkbox">Checkbox</option>
|
<option value="checkbox">Checkbox</option>
|
||||||
<option value="dropdown">Dropdown</option>
|
<option value="dropdown">Dropdown</option>
|
||||||
|
<option value="text">Text</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" id="question-text-${questionIndex}" name="questions[${questionIndex}][text]" class="form-control question-input" placeholder="Type your question here" required>
|
<input type="text" id="question-text-${questionIndex}" name="questions[${questionIndex}][text]" class="form-control question-input" placeholder="Type your question here" required>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group form-check">
|
||||||
|
<input type="checkbox" id="question-required-{{ $index }}"
|
||||||
|
name="questions[{{ $index }}][required]" class="form-check-input"
|
||||||
|
{{ $question->required ? 'checked' : '' }}>
|
||||||
|
<label for="question-required-{{ $index }}" class="form-check-label">Required</label>
|
||||||
|
</div>
|
||||||
<div class="form-group options-container">
|
<div class="form-group options-container">
|
||||||
<label>Options</label>
|
<label>Options</label>
|
||||||
<button type="button" class="btn btn-secondary" onclick="addOption(this)">Add Option</button>
|
<button type="button" class="btn btn-secondary" onclick="addOption(this)">Add Option</button>
|
||||||
</div>
|
|
||||||
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
||||||
<img src="{{ asset('images/bin.png') }}" alt="" width="20px" height="20px" />
|
<img src="{{ asset('images/bin.png') }}" alt="" width="20px" height="20px" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
questionsSection.append(questionHtml);
|
questionsSection.append(questionHtml);
|
||||||
|
@ -167,9 +170,35 @@
|
||||||
|
|
||||||
function deleteQuestion(button) {
|
function deleteQuestion(button) {
|
||||||
$(button).closest('.question').remove();
|
$(button).closest('.question').remove();
|
||||||
|
updateQuestionIndices();
|
||||||
updateAddButtonPosition();
|
updateAddButtonPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateQuestionIndices() {
|
||||||
|
$('#questions-section .question').each((index, element) => {
|
||||||
|
$(element).attr('data-index', index);
|
||||||
|
$(element).find('.question-type').attr('name', `questions[${index}][type]`);
|
||||||
|
$(element).find('.question-input').attr('name', `questions[${index}][text]`);
|
||||||
|
$(element).find('.question-input').attr('id', `question-text-${index}`);
|
||||||
|
$(element).find('.form-check-input').attr('name', `questions[${index}][required]`);
|
||||||
|
$(element).find('.form-check-input').attr('id', `question-required-${index}`);
|
||||||
|
$(element).find('.options-container').find('.option-input').each((optionIndex, optionElement) => {
|
||||||
|
$(optionElement).attr('name', `questions[${index}][options][${optionIndex}]`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleQuestionTypeChange(selectElement) {
|
||||||
|
const selectedType = $(selectElement).val();
|
||||||
|
const optionsContainer = $(selectElement).closest('.question').find('.options-container');
|
||||||
|
|
||||||
|
if (selectedType === 'text') {
|
||||||
|
optionsContainer.hide();
|
||||||
|
} else {
|
||||||
|
optionsContainer.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateAddButtonPosition() {
|
function updateAddButtonPosition() {
|
||||||
const questions = document.querySelectorAll("#questions-section .question");
|
const questions = document.querySelectorAll("#questions-section .question");
|
||||||
const sidebar = document.getElementById("moveableDiv");
|
const sidebar = document.getElementById("moveableDiv");
|
||||||
|
@ -195,20 +224,31 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('#profileMenuButton').on('click', function() {
|
$('#profileMenuButton').click(function () {
|
||||||
$('#profileMenu').toggleClass('hidden');
|
$('#profileMenu').toggleClass('hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', function(e) {
|
$(document).click(function (event) {
|
||||||
if (!$(e.target).closest('#profileMenuButton').length && !$(e.target).closest(
|
if (!$(event.target).closest('#profileMenuButton, #profileMenu').length) {
|
||||||
'#profileMenu').length) {
|
|
||||||
$('#profileMenu').addClass('hidden');
|
$('#profileMenu').addClass('hidden');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.question-type').each((index, element) => {
|
||||||
|
handleQuestionTypeChange(element);
|
||||||
|
});
|
||||||
|
|
||||||
updateAddButtonPosition();
|
updateAddButtonPosition();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,11 @@
|
||||||
<th
|
<th
|
||||||
class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
||||||
Responses</th>
|
Responses</th>
|
||||||
<th
|
<th class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
||||||
class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
Status</th>
|
||||||
Actions</th>
|
<th></th>
|
||||||
|
<th>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -93,11 +95,20 @@
|
||||||
<a href="{{ route('responses.viewResponses', $form) }}"
|
<a href="{{ route('responses.viewResponses', $form) }}"
|
||||||
class="text-blue-500 hover:underline">View Responses</a>
|
class="text-blue-500 hover:underline">View Responses</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="py-4 px-6 border-b border-gray-200">
|
||||||
|
@if ($form->is_published)
|
||||||
|
Published
|
||||||
|
@else
|
||||||
|
Unpublished
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
<td class="py-8 px-6 border-b border-gray-200 flex items-center space-x-10">
|
<td class="py-8 px-6 border-b border-gray-200 flex items-center space-x-10">
|
||||||
@if (!$form->is_published)
|
@if (!$form->is_published)
|
||||||
<a href="{{ route('forms.edit', $form) }}"
|
<a href="{{ route('forms.edit', $form) }}"
|
||||||
class="text-green-500 hover:underline">Edit</a>
|
class="text-green-500 hover:underline">Edit</a>
|
||||||
@endif
|
@endif
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
<form action="{{ route('forms.destroy', $form) }}" method="POST"
|
<form action="{{ route('forms.destroy', $form) }}" method="POST"
|
||||||
class="inline-block">
|
class="inline-block">
|
||||||
@csrf
|
@csrf
|
||||||
|
|
|
@ -1,133 +1,3 @@
|
||||||
{{-- <!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
||||||
<title>Show Form - {{ $form->title }}</title>
|
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="form_header">
|
|
||||||
<div class="form_header_left">
|
|
||||||
<a href="/forms"><img src="{{ asset('images/google-form.png') }}" class="form_header_icon" height="45px" width="40px" /></a>
|
|
||||||
<input type="text" name="title" id="form-title-nav" placeholder="Untitled Form" class="form_name" value="{{ $form->title }}" readonly />
|
|
||||||
<img src="{{ asset('images/folder.png') }}" alt="" class="form_header_icon" height="20px" width="20px" />
|
|
||||||
<img src="{{ asset('images/star.svg') }}" alt="" class="form_header_icon" />
|
|
||||||
</div>
|
|
||||||
<div class="form_header_right">
|
|
||||||
<span><img src="{{ asset('images/palette-svgrepo-com.svg') }}" alt="pallette" height="20px" width="20px" /></span>
|
|
||||||
<span><img src="{{ asset('images/view.png') }}" alt="eye" height="20px" width="20px" onclick="previewForm()" /></span>
|
|
||||||
<span><img src="{{ asset('images/undo.png') }}" alt="" height="20px" width="20px" /></span>
|
|
||||||
<span><img src="{{ asset('images/forward.png') }}" alt="" height="20px" width="20px" /></span>
|
|
||||||
<button class="btn">Send</button>
|
|
||||||
<span><img src="{{ asset('images/menu.png') }}" alt="menu" height="30px" width="30px" /></span>
|
|
||||||
<span><img src="{{ asset('images/user.png') }}" alt="" height="30px" width="30px" /></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="box">
|
|
||||||
<input type="radio" class="tab-toggle" name="tab-toggle" id="tab1" checked />
|
|
||||||
<input type="radio" class="tab-toggle" name="tab-toggle" id="tab2" />
|
|
||||||
<input type="radio" class="tab-toggle" name="tab-toggle" id="tab3" />
|
|
||||||
|
|
||||||
<ul class="tab-list">
|
|
||||||
<li class="tab-item">
|
|
||||||
<label class="tab-trigger" for="tab1"><b>Questions</b></label>
|
|
||||||
</li>
|
|
||||||
<li class="tab-item">
|
|
||||||
<label class="tab-trigger" for="tab2"><b>Responses</b></label>
|
|
||||||
</li>
|
|
||||||
<li class="tab-item">
|
|
||||||
<label class="tab-trigger" for="tab3"><b>Settings</b></label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<form id="publish-form" method="POST" action="{{ route('forms.update', $form) }}">
|
|
||||||
@csrf
|
|
||||||
@method('PUT')
|
|
||||||
<div class="question_form">
|
|
||||||
<br />
|
|
||||||
<div class="section">
|
|
||||||
<div class="question_title_section">
|
|
||||||
<div class="question_form_top">
|
|
||||||
<input type="text" id="form-title" name="title" class="question_form_top_name form-control" style="color: black" placeholder="Untitled Form" value="{{ $form->title }}" readonly />
|
|
||||||
<input type="text" name="description" id="form-description" class="question_form_top_desc" style="color: black" placeholder="Form Description" value="{{ $form->description }}" readonly />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="questions_section">
|
|
||||||
@foreach ($form->questions as $index => $question)
|
|
||||||
<div class="question">
|
|
||||||
<select class="form-control question_type" name="questions[{{ $index }}][type]" onchange="changeQuestionType(this)" disabled>
|
|
||||||
<option value="multiple_choice" {{ $question->type === 'multiple_choice' ? 'selected' : '' }}>Multiple Choice</option>
|
|
||||||
<option value="checkbox" {{ $question->type === 'checkbox' ? 'selected' : '' }}>Checkbox</option>
|
|
||||||
<option value="dropdown" {{ $question->type === 'dropdown' ? 'selected' : '' }}>Dropdown</option>
|
|
||||||
</select>
|
|
||||||
<input type="text" name="questions[{{ $index }}][text]" class="form-control question-input" placeholder="Type your question here" value="{{ $question->question_text }}" readonly />
|
|
||||||
@if ($question->options)
|
|
||||||
<div class="options-container">
|
|
||||||
@foreach (json_decode($question->options) as $optionIndex => $option)
|
|
||||||
<div class="option">
|
|
||||||
<input type="text" name="questions[{{ $index }}][options][{{ $optionIndex }}]" class="form-control option-input" placeholder="Option" value="{{ $option }}" readonly />
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="btnsub">
|
|
||||||
<span>
|
|
||||||
<a href="{{ route('forms.edit', $form) }}" class="btnsave btn btn-secondary">Edit</a>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span>
|
|
||||||
<button type="submit" name="publish" value="publish" class="btnsave btn btn-secondary">
|
|
||||||
{{ $form->is_published ? 'Unpublish' : 'Publish' }}
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span>
|
|
||||||
<a href="/forms" class="btnsave btn btn-secondary">Return</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
document.querySelector('button[name="publish"]').addEventListener('click', function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
document.getElementById('publish-form').action = "{{ route('forms.update', $form) }}";
|
|
||||||
document.getElementById('publish-form').submit();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script src="{{ asset('js/script.js') }}"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--}}
|
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@ -194,6 +64,7 @@
|
||||||
<option value="multiple_choice" {{ $question->type === 'multiple_choice' ? 'selected' : '' }}>Multiple Choice</option>
|
<option value="multiple_choice" {{ $question->type === 'multiple_choice' ? 'selected' : '' }}>Multiple Choice</option>
|
||||||
<option value="checkbox" {{ $question->type === 'checkbox' ? 'selected' : '' }}>Checkbox</option>
|
<option value="checkbox" {{ $question->type === 'checkbox' ? 'selected' : '' }}>Checkbox</option>
|
||||||
<option value="dropdown" {{ $question->type === 'dropdown' ? 'selected' : '' }}>Dropdown</option>
|
<option value="dropdown" {{ $question->type === 'dropdown' ? 'selected' : '' }}>Dropdown</option>
|
||||||
|
<option value="text" {{ $question->type === 'text' ? 'selected' : '' }}>Text</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="text" name="questions[{{ $index }}][text]" class="form-control question-input mb-3" placeholder="Type your question here" value="{{ $question->question_text }}" readonly />
|
<input type="text" name="questions[{{ $index }}][text]" class="form-control question-input mb-3" placeholder="Type your question here" value="{{ $question->question_text }}" readonly />
|
||||||
@if ($question->options)
|
@if ($question->options)
|
||||||
|
@ -210,9 +81,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="btnsub text-center mt-4">
|
<div class="btnsub text-center mt-4">
|
||||||
<span>
|
<form action="{{ route('forms.publish', $form->id) }}" method="POST">
|
||||||
<a href="{{ route('forms.index') }}" class="btnsave btn btn-secondary">Return to Forms</a>
|
@csrf
|
||||||
</span>
|
@method('PATCH')
|
||||||
|
<span><button type="submit" name="publish" value="publish" class="btnsave btn btn-secondary">
|
||||||
|
{{ $form->is_published ? 'Unpublish' : 'Publish' }}
|
||||||
|
</button></span>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<span><a href="{{ route('forms.index') }}" class="btnsave btn btn-secondary">Return to Forms</a></span>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{ asset('js/script.js') }}"></script>
|
<script src="{{ asset('js/script.js') }}"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -1,54 +1,7 @@
|
||||||
{{-- @extends('layouts.app')
|
{{-- @extends('layouts.app')
|
||||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
|
||||||
@section('content')
|
|
||||||
<div class="container mx-auto py-8">
|
|
||||||
<h1 class="text-3xl font-semibold">{{ $form->title }}</h1>
|
|
||||||
<p class="text-gray-700 mt-2">{{ $form->description }}</p>
|
|
||||||
|
|
||||||
<form action="{{ route('responses.submitForm', $form) }}" method="POST" class="mt-8">
|
|
||||||
@csrf
|
|
||||||
@foreach ($questions as $question)
|
|
||||||
<div class="mt-6">
|
|
||||||
<label class="block font-medium text-gray-800">{{ $question->question_text }}</label>
|
|
||||||
@if ($question->type == 'multiple_choice')
|
|
||||||
@foreach (json_decode($question->options) as $option)
|
|
||||||
<label class="inline-flex items-center mt-2">
|
|
||||||
<input class="form-radio text-purple-600" type="radio" name="answers[{{ $question->id }}]" value="{{ $option }}">
|
|
||||||
<span class="ml-2 text-gray-700">{{ $option }}</span>
|
|
||||||
</label>
|
|
||||||
@endforeach
|
|
||||||
@elseif($question->type == 'checkbox')
|
|
||||||
@foreach (json_decode($question->options) as $option)
|
|
||||||
<label class="inline-flex items-center mt-2">
|
|
||||||
<input class="form-checkbox text-purple-600" type="checkbox" name="answers[{{ $question->id }}][]" value="{{ $option }}">
|
|
||||||
<span class="ml-2 text-gray-700">{{ $option }}</span>
|
|
||||||
</label>
|
|
||||||
@endforeach
|
|
||||||
@elseif($question->type == 'dropdown')
|
|
||||||
<select class="form-select mt-2 block w-full p-2 border border-gray-300 rounded-md bg-white shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm" name="answers[{{ $question->id }}]">
|
|
||||||
@foreach (json_decode($question->options) as $option)
|
|
||||||
<option value="{{ $option }}">{{ $option }}</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
@elseif($question->type == 'short_answer')
|
|
||||||
<input type="text" name="answers[{{ $question->id }}]" class="form-input mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm">
|
|
||||||
@elseif($question->type == 'long_answer')
|
|
||||||
<textarea name="answers[{{ $question->id }}]" class="form-textarea mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm"></textarea>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
|
|
||||||
<button type="submit" class="mt-6 inline-flex items-center px-4 py-2 bg-purple-700 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-purple-800 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 focus:ring-offset-purple-200">
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
@endsection
|
|
||||||
--}}
|
|
||||||
|
|
||||||
|
|
||||||
@extends('layouts.app')
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="container mx-auto py-8 px-4 md:px-0">
|
<div class="container mx-auto py-8 px-4 md:px-0">
|
||||||
<div class="bg-white shadow-md rounded-lg p-6">
|
<div class="bg-white shadow-md rounded-lg p-6">
|
||||||
|
@ -80,9 +33,7 @@
|
||||||
<option value="{{ $option }}">{{ $option }}</option>
|
<option value="{{ $option }}">{{ $option }}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@elseif($question->type == 'short_answer')
|
@elseif($question->type == 'text')
|
||||||
<input type="text" name="answers[{{ $question->id }}]" class="form-input mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm">
|
|
||||||
@elseif($question->type == 'long_answer')
|
|
||||||
<textarea name="answers[{{ $question->id }}]" class="form-textarea mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm"></textarea>
|
<textarea name="answers[{{ $question->id }}]" class="form-textarea mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm"></textarea>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@ -94,4 +45,154 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
document.getElementById('responseForm').addEventListener('submit', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const form = event.target;
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
fetch(form.action, {
|
||||||
|
method: form.method,
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Success!',
|
||||||
|
text: 'Form submitted successfully.',
|
||||||
|
icon: 'success',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
window.location.href = '/forms';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error!',
|
||||||
|
text: 'Failed to submit form.',
|
||||||
|
icon: 'error',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error!',
|
||||||
|
text: 'An error occurred while submitting the form.',
|
||||||
|
icon: 'error',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endsection --}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@extends('layouts.app')
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container mx-auto py-8 px-4 md:px-0">
|
||||||
|
<div class="bg-white shadow-md rounded-lg p-6">
|
||||||
|
<h1 class="text-3xl font-semibold text-gray-900">{{ $form->title }}</h1>
|
||||||
|
<p class="text-gray-600 mt-2">{{ $form->description }}</p>
|
||||||
|
|
||||||
|
<form id="responseForm" action="{{ route('responses.submitForm', $form) }}" method="POST" class="mt-8">
|
||||||
|
@csrf
|
||||||
|
@foreach ($questions as $question)
|
||||||
|
<div class="mt-6">
|
||||||
|
<label class="block font-medium text-base text-gray-800 mb-2">{{ $question->question_text }}</label>
|
||||||
|
@if ($question->type == 'multiple_choice')
|
||||||
|
@foreach (json_decode($question->options) as $option)
|
||||||
|
<label class="flex items-center mt-2">
|
||||||
|
<input class="form-radio text-base text-purple-600 h-4 w-4" type="radio" name="answers[{{ $question->id }}]" value="{{ $option }}">
|
||||||
|
<span class="ml-2 text-gray-700">{{ $option }}</span>
|
||||||
|
</label>
|
||||||
|
@endforeach
|
||||||
|
@elseif($question->type == 'checkbox')
|
||||||
|
@foreach (json_decode($question->options) as $option)
|
||||||
|
<label class="flex items-center mt-2">
|
||||||
|
<input class="form-checkbox text-purple-600 h-4 w-4" type="checkbox" name="answers[{{ $question->id }}][]" value="{{ $option }}">
|
||||||
|
<span class="ml-2 text-gray-700">{{ $option }}</span>
|
||||||
|
</label>
|
||||||
|
@endforeach
|
||||||
|
@elseif($question->type == 'dropdown')
|
||||||
|
<select class="form-select mt-2 block w-full p-2 border border-gray-300 rounded-md bg-white shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm" name="answers[{{ $question->id }}]">
|
||||||
|
@foreach (json_decode($question->options) as $option)
|
||||||
|
<option value="{{ $option }}">{{ $option }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
@elseif($question->type == 'text')
|
||||||
|
<textarea name="answers[{{ $question->id }}]" class="form-textarea mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm"></textarea>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
<button type="submit" class="mt-8 w-full md:w-auto inline-flex justify-center items-center px-6 py-3 bg-purple-700 border border-transparent rounded-md font-semibold text-white text-lg uppercase tracking-widest hover:bg-purple-800 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('responseForm').addEventListener('submit', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const form = event.target;
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
fetch(form.action, {
|
||||||
|
method: form.method,
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Success!',
|
||||||
|
text: 'Form submitted successfully.',
|
||||||
|
icon: 'success',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
window.location.href = '/forms';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error!',
|
||||||
|
text: 'Failed to submit form.',
|
||||||
|
icon: 'error',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Success!',
|
||||||
|
text: 'Form Submitted Successfully',
|
||||||
|
icon: 'success',
|
||||||
|
confirmButtonText: 'OK'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
@ -22,7 +22,7 @@ Route::middleware(['auth'])->group(function () {
|
||||||
Route::put('/forms/{form}', [FormController::class, 'update'])->name('forms.update');
|
Route::put('/forms/{form}', [FormController::class, 'update'])->name('forms.update');
|
||||||
Route::delete('/forms/{form}', [FormController::class, 'destroy'])->name('forms.destroy');
|
Route::delete('/forms/{form}', [FormController::class, 'destroy'])->name('forms.destroy');
|
||||||
Route::get('/forms/{form}/preview', [FormController::class, 'preview'])->name('forms.preview');
|
Route::get('/forms/{form}/preview', [FormController::class, 'preview'])->name('forms.preview');
|
||||||
|
Route::patch('/forms/{form}/publish', [FormController::class, 'togglePublish'])->name('forms.publish');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Response routes
|
// Response routes
|
||||||
|
|
Loading…
Reference in New Issue