Code and bug fixes
This commit is contained in:
parent
e747614bd3
commit
0d8c522732
|
@ -55,7 +55,7 @@ class FormController extends Controller
|
||||||
|
|
||||||
|
|
||||||
public function createWithTemplate($template)
|
public function createWithTemplate($template)
|
||||||
{
|
{
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
switch ($template) {
|
switch ($template) {
|
||||||
|
@ -80,7 +80,6 @@ Contact us at (123) 456-7890 or no_reply@example.com
|
||||||
'questions' => [
|
'questions' => [
|
||||||
['type' => 'text', 'question_text' => 'Can you attend?'],
|
['type' => 'text', 'question_text' => 'Can you attend?'],
|
||||||
['type' => 'text', 'question_text' => 'Number of Guests'],
|
['type' => 'text', 'question_text' => 'Number of Guests'],
|
||||||
// Add more questions as needed
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
|
@ -92,20 +91,19 @@ Contact us at (123) 456-7890 or no_reply@example.com
|
||||||
'questions' => [
|
'questions' => [
|
||||||
['type' => 'text', 'question_text' => 'Name'],
|
['type' => 'text', 'question_text' => 'Name'],
|
||||||
['type' => 'text', 'question_text' => 'RSVP Status'],
|
['type' => 'text', 'question_text' => 'RSVP Status'],
|
||||||
// Add more questions as needed
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('forms.create', ['data' => $data]);
|
return view('forms.create', ['data' => $data]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'title' => 'required|string|max:255',
|
'title' => 'required|string|max:255',
|
||||||
|
@ -142,7 +140,7 @@ Contact us at (123) 456-7890 or no_reply@example.com
|
||||||
Log::error('Error saving form: ' . $e->getMessage(), ['exception' => $e]);
|
Log::error('Error saving form: ' . $e->getMessage(), ['exception' => $e]);
|
||||||
return response()->json(['success' => false, 'message' => 'Error saving form'], 500);
|
return response()->json(['success' => false, 'message' => 'Error saving form'], 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show(Form $form)
|
public function show(Form $form)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,21 +6,13 @@ use Illuminate\Http\Request;
|
||||||
|
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('auth');
|
$this->middleware('auth');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the application dashboard.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\Support\Renderable
|
|
||||||
*/
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return view('forms.index');
|
return view('forms.index');
|
||||||
|
|
|
@ -17,14 +17,14 @@ class QuestionController extends Controller
|
||||||
|
|
||||||
public function store(Form $form, Request $request)
|
public function store(Form $form, Request $request)
|
||||||
{
|
{
|
||||||
// Validate question data
|
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'type' => 'required|string|in:multiple_choice,checkbox,dropdown,short_answer,long_answer',
|
'type' => 'required|string|in:multiple_choice,checkbox,dropdown,short_answer,long_answer',
|
||||||
'question_text' => 'required|string',
|
'question_text' => 'required|string',
|
||||||
'options' => 'nullable|array', // If needed based on question type
|
'options' => 'nullable|array',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Create new question for the form
|
|
||||||
$question = new Question();
|
$question = new Question();
|
||||||
$question->form_id = $form->id;
|
$question->form_id = $form->id;
|
||||||
$question->type = $validatedData['type'];
|
$question->type = $validatedData['type'];
|
||||||
|
@ -42,14 +42,14 @@ class QuestionController extends Controller
|
||||||
|
|
||||||
public function update(Form $form, Question $question, Request $request)
|
public function update(Form $form, Question $question, Request $request)
|
||||||
{
|
{
|
||||||
// Validate updated question data
|
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'type' => 'required|string|in:multiple_choice,checkbox,dropdown,short_answer,long_answer',
|
'type' => 'required|string|in:multiple_choice,checkbox,dropdown,short_answer,long_answer',
|
||||||
'question_text' => 'required|string',
|
'question_text' => 'required|string',
|
||||||
'options' => 'nullable|array', // If needed based on question type
|
'options' => 'nullable|array',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Update question details
|
|
||||||
$question->type = $validatedData['type'];
|
$question->type = $validatedData['type'];
|
||||||
$question->question_text = $validatedData['question_text'];
|
$question->question_text = $validatedData['question_text'];
|
||||||
$question->options = $validatedData['options'] ?? null;
|
$question->options = $validatedData['options'] ?? null;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use App\Models\Form;
|
use App\Models\Form;
|
||||||
|
@ -22,23 +23,23 @@ class ResponseController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
public function showSuccess(Form $form)
|
public function showSuccess(Form $form)
|
||||||
{
|
{
|
||||||
return view('responses.success', compact('form'));
|
return view('responses.success', compact('form'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Display a specific response
|
|
||||||
public function viewResponse(Form $form, $responseId)
|
public function viewResponse(Form $form, $responseId)
|
||||||
{
|
{
|
||||||
// Get all responses with the same response_id
|
|
||||||
$responses = Response::where('response_id', $responseId)
|
$responses = Response::where('response_id', $responseId)
|
||||||
->where('form_id', $form->id)
|
->where('form_id', $form->id)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
// Get all questions for the form
|
|
||||||
$questions = Question::where('form_id', $form->id)->get()->keyBy('id');
|
$questions = Question::where('form_id', $form->id)->get()->keyBy('id');
|
||||||
|
|
||||||
// Aggregate data for statistics
|
|
||||||
$statistics = [];
|
$statistics = [];
|
||||||
foreach ($questions as $question) {
|
foreach ($questions as $question) {
|
||||||
$statistics[$question->id] = [
|
$statistics[$question->id] = [
|
||||||
|
@ -57,21 +58,21 @@ class ResponseController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('responses.viewResponse', compact('form', 'responses', 'questions', 'statistics'));
|
return view('responses.viewResponse', compact('form', 'responses', 'questions', 'statistics'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function viewResponses(Form $form)
|
public function viewResponses(Form $form)
|
||||||
{
|
{
|
||||||
// Get all responses for the form, grouped by response_id
|
|
||||||
$responses = Response::where('form_id', $form->id)
|
$responses = Response::where('form_id', $form->id)
|
||||||
->orderBy('submitted_at', 'desc')
|
->orderBy('submitted_at', 'desc')
|
||||||
->get()
|
->get()
|
||||||
->groupBy('response_id');
|
->groupBy('response_id');
|
||||||
|
|
||||||
// Get all questions for the form
|
|
||||||
$questions = Question::where('form_id', $form->id)->get()->keyBy('id');
|
$questions = Question::where('form_id', $form->id)->get()->keyBy('id');
|
||||||
|
|
||||||
// Aggregate data for statistics
|
|
||||||
$statistics = [];
|
$statistics = [];
|
||||||
foreach ($questions as $question) {
|
foreach ($questions as $question) {
|
||||||
$statistics[$question->id] = [
|
$statistics[$question->id] = [
|
||||||
|
@ -92,7 +93,7 @@ public function viewResponses(Form $form)
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('responses.viewResponses', compact('form', 'responses', 'statistics', 'questions'));
|
return view('responses.viewResponses', compact('form', 'responses', 'statistics', 'questions'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function showForm(Form $form)
|
public function showForm(Form $form)
|
||||||
|
@ -106,22 +107,22 @@ public function viewResponses(Form $form)
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submitForm(Request $request, Form $form)
|
public function submitForm(Request $request, Form $form)
|
||||||
{
|
{
|
||||||
Log::info($request->all()); // Log the entire request data for debugging
|
Log::info($request->all());
|
||||||
|
|
||||||
|
|
||||||
// Fetch all questions for the form
|
|
||||||
$questions = $form->questions;
|
$questions = $form->questions;
|
||||||
|
|
||||||
// Extract IDs of required questions
|
|
||||||
$requiredQuestionIds = $questions->where('required', true)->pluck('id')->toArray();
|
$requiredQuestionIds = $questions->where('required', true)->pluck('id')->toArray();
|
||||||
|
|
||||||
// Validate and process form submission
|
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'answers' => 'required|array',
|
'answers' => 'required|array',
|
||||||
'answers.*' => 'required', // Ensure all answers are provided
|
'answers.*' => 'required',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Ensure all required questions are answered
|
|
||||||
foreach ($requiredQuestionIds as $requiredQuestionId) {
|
foreach ($requiredQuestionIds as $requiredQuestionId) {
|
||||||
if (!array_key_exists($requiredQuestionId, $validatedData['answers'])) {
|
if (!array_key_exists($requiredQuestionId, $validatedData['answers'])) {
|
||||||
return redirect()->back()
|
return redirect()->back()
|
||||||
|
@ -130,15 +131,15 @@ public function viewResponses(Form $form)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::info($validatedData); // Log the validated data for debugging
|
Log::info($validatedData);
|
||||||
|
|
||||||
|
|
||||||
// Generate a UUID for response_id
|
|
||||||
$responseId = Uuid::uuid4()->toString();
|
$responseId = Uuid::uuid4()->toString();
|
||||||
|
|
||||||
// Save each question's response
|
|
||||||
foreach ($validatedData['answers'] as $questionId => $answer) {
|
foreach ($validatedData['answers'] as $questionId => $answer) {
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
$response->response_id = $responseId; // Assign the generated UUID
|
$response->response_id = $responseId;
|
||||||
$response->question_id = $questionId;
|
$response->question_id = $questionId;
|
||||||
$response->form_id = $form->id;
|
$response->form_id = $form->id;
|
||||||
$response->user_id = auth()->id();
|
$response->user_id = auth()->id();
|
||||||
|
@ -149,10 +150,5 @@ 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.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,25 +21,31 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeQuestionType(selectElement) {
|
function changeQuestionType(selectElement) {
|
||||||
const questionContainer = selectElement.closest('.question');
|
const questionContainer = selectElement.closest(".question");
|
||||||
const optionsContainer = questionContainer.querySelector('.options-container');
|
const optionsContainer =
|
||||||
const addOptionButton = questionContainer.querySelector('.btn-secondary');
|
questionContainer.querySelector(".options-container");
|
||||||
|
const addOptionButton =
|
||||||
|
questionContainer.querySelector(".btn-secondary");
|
||||||
const questionType = selectElement.value;
|
const questionType = selectElement.value;
|
||||||
|
|
||||||
// Clear the options container
|
// Clear the options container
|
||||||
optionsContainer.innerHTML = '';
|
optionsContainer.innerHTML = "";
|
||||||
|
|
||||||
if (questionType === 'multiple_choice' || questionType === 'checkbox' || questionType === 'dropdown') {
|
if (
|
||||||
const optionDiv = document.createElement('div');
|
questionType === "multiple_choice" ||
|
||||||
optionDiv.className = 'option d-flex align-items-center mb-2';
|
questionType === "checkbox" ||
|
||||||
|
questionType === "dropdown"
|
||||||
|
) {
|
||||||
|
const optionDiv = document.createElement("div");
|
||||||
|
optionDiv.className = "option d-flex align-items-center mb-2";
|
||||||
optionDiv.innerHTML = `
|
optionDiv.innerHTML = `
|
||||||
<input type="text" name="option" class="form-control option-input" placeholder="Option 1" />
|
<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>
|
<span class="delete-option ml-2 text-danger" onclick="deleteOption(this)" style="cursor: pointer;">✕</span>
|
||||||
`;
|
`;
|
||||||
optionsContainer.appendChild(optionDiv);
|
optionsContainer.appendChild(optionDiv);
|
||||||
addOptionButton.style.display = 'inline-block'; // Show the "Add Option" button
|
addOptionButton.style.display = "inline-block"; // Show the "Add Option" button
|
||||||
} else if (questionType === 'text') {
|
} else if (questionType === "text") {
|
||||||
addOptionButton.style.display = 'none'; // Hide the "Add Option" button
|
addOptionButton.style.display = "none"; // Hide the "Add Option" button
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +110,9 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
sidebar.style.transform = `translateY(${newPosition}px)`;
|
sidebar.style.transform = `translateY(${newPosition}px)`;
|
||||||
console.log(`Moving sidebar to: ${newPosition}px`);
|
console.log(`Moving sidebar to: ${newPosition}px`);
|
||||||
} else {
|
} else {
|
||||||
sidebar.style.transform = `translateY(${containerHeight - sidebarHeight}px)`;
|
sidebar.style.transform = `translateY(${
|
||||||
|
containerHeight - sidebarHeight
|
||||||
|
}px)`;
|
||||||
console.log(`Moving sidebar to bottom of container`);
|
console.log(`Moving sidebar to bottom of container`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,7 +123,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
function saveForm() {
|
function saveForm() {
|
||||||
const formTitle = document.getElementById("form-title").value;
|
const formTitle = document.getElementById("form-title").value;
|
||||||
const formDescription = document.getElementById("form-description").value;
|
const formDescription =
|
||||||
|
document.getElementById("form-description").value;
|
||||||
const questions = document.querySelectorAll(".question");
|
const questions = document.querySelectorAll(".question");
|
||||||
let formData = [];
|
let formData = [];
|
||||||
|
|
||||||
|
@ -123,26 +132,34 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
questions.forEach((question) => {
|
questions.forEach((question) => {
|
||||||
const questionType = question.querySelector("select").value;
|
const questionType = question.querySelector("select").value;
|
||||||
const questionText = question.querySelector(".question-input").value;
|
const questionText =
|
||||||
const isRequired = question.querySelector(".required-checkbox").checked;
|
question.querySelector(".question-input").value;
|
||||||
|
const isRequired =
|
||||||
|
question.querySelector(".required-checkbox").checked;
|
||||||
let options = [];
|
let options = [];
|
||||||
|
|
||||||
if (questionType === 'multiple_choice' || questionType === 'checkbox' || questionType === 'dropdown') {
|
if (
|
||||||
options = Array.from(question.querySelectorAll(".option-input")).map((input) => input.value);
|
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
|
required: isRequired,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log({
|
console.log({
|
||||||
type: questionType,
|
type: questionType,
|
||||||
text: questionText,
|
text: questionText,
|
||||||
options: options,
|
options: options,
|
||||||
required: isRequired
|
required: isRequired,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -158,17 +175,16 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
const data = {
|
const data = {
|
||||||
title: formTitle,
|
title: formTitle,
|
||||||
description: formDescription,
|
description: formDescription,
|
||||||
questions: formData
|
questions: formData,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
|
|
||||||
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),
|
||||||
})
|
})
|
||||||
|
@ -176,10 +192,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Success!',
|
title: "Success!",
|
||||||
text: 'Form saved successfully.',
|
text: "Form saved successfully.",
|
||||||
icon: 'success',
|
icon: "success",
|
||||||
confirmButtonText: 'OK'
|
confirmButtonText: "OK",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
window.location.href = "/forms";
|
window.location.href = "/forms";
|
||||||
|
@ -187,10 +203,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Error!',
|
title: "Error!",
|
||||||
text: 'Failed to save form.',
|
text: "Failed to save form.",
|
||||||
icon: 'error',
|
icon: "error",
|
||||||
confirmButtonText: 'OK'
|
confirmButtonText: "OK",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -200,14 +216,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
window.addNewQuestion = addNewQuestion;
|
window.addNewQuestion = addNewQuestion;
|
||||||
window.deleteQuestion = deleteQuestion;
|
window.deleteQuestion = deleteQuestion;
|
||||||
window.addOption = addOption;
|
window.addOption = addOption;
|
||||||
|
@ -217,7 +225,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
// document.getElementById("add-question-button").addEventListener("click", addNewQuestion);
|
// document.getElementById("add-question-button").addEventListener("click", addNewQuestion);
|
||||||
|
|
||||||
document.getElementById("questions_section").addEventListener("DOMNodeInserted", updateAddButtonPosition);
|
document
|
||||||
document.getElementById("questions_section").addEventListener("DOMNodeRemoved", updateAddButtonPosition);
|
.getElementById("questions_section")
|
||||||
|
.addEventListener("DOMNodeInserted", updateAddButtonPosition);
|
||||||
|
document
|
||||||
|
.getElementById("questions_section")
|
||||||
|
.addEventListener("DOMNodeRemoved", updateAddButtonPosition);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
// statistics.js
|
|
||||||
|
|
||||||
// Function to fetch responses from backend
|
|
||||||
function fetchResponses() {
|
|
||||||
return fetch('/api/responses') // Replace with your actual API endpoint
|
|
||||||
.then(response => response.json())
|
|
||||||
.catch(error => console.error('Error fetching responses:', error));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to process fetched responses data
|
|
||||||
function processDataForCharts(responses, questions) {
|
|
||||||
const pieData = {};
|
|
||||||
const barData = {};
|
|
||||||
|
|
||||||
responses.forEach(response => {
|
|
||||||
const question = questions[response.question_id];
|
|
||||||
const decodedAnswers = JSON.parse(response.answers);
|
|
||||||
|
|
||||||
// Process data for pie chart
|
|
||||||
if (!pieData[question.question_text]) {
|
|
||||||
pieData[question.question_text] = {};
|
|
||||||
}
|
|
||||||
if (question.type === 'multiple_choice' || question.type === 'checkbox') {
|
|
||||||
JSON.parse(question.options).forEach(option => {
|
|
||||||
pieData[question.question_text][option] = (pieData[question.question_text][option] || 0) +
|
|
||||||
(decodedAnswers.includes(option) ? 1 : 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process data for bar graph (assuming numerical responses)
|
|
||||||
if (question.type === 'short_answer' || question.type === 'long_answer') {
|
|
||||||
if (!barData[question.question_text]) {
|
|
||||||
barData[question.question_text] = { total: 0, count: 0 };
|
|
||||||
}
|
|
||||||
barData[question.question_text].total += parseFloat(response.answers);
|
|
||||||
barData[question.question_text].count++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Calculate averages for bar graph
|
|
||||||
Object.keys(barData).forEach(key => {
|
|
||||||
barData[key].average = barData[key].total / barData[key].count;
|
|
||||||
});
|
|
||||||
|
|
||||||
return { pieData, barData };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to render charts using Chart.js
|
|
||||||
function renderCharts(pieData, barData) {
|
|
||||||
// Render Pie Chart
|
|
||||||
const pieChartCanvas = document.getElementById('pieChart');
|
|
||||||
new Chart(pieChartCanvas.getContext('2d'), {
|
|
||||||
type: 'pie',
|
|
||||||
data: {
|
|
||||||
labels: Object.keys(pieData),
|
|
||||||
datasets: Object.keys(pieData).map(question => ({
|
|
||||||
label: question,
|
|
||||||
data: Object.values(pieData[question]),
|
|
||||||
backgroundColor: getRandomColors(Object.values(pieData[question]).length),
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'top',
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
callbacks: {
|
|
||||||
label: function(context) {
|
|
||||||
let label = context.label || '';
|
|
||||||
if (context.parsed.y !== null) {
|
|
||||||
label += ': ' + context.parsed.y;
|
|
||||||
}
|
|
||||||
return label;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Render Bar Graph
|
|
||||||
const barGraphCanvas = document.getElementById('barGraph');
|
|
||||||
new Chart(barGraphCanvas.getContext('2d'), {
|
|
||||||
type: 'bar',
|
|
||||||
data: {
|
|
||||||
labels: Object.keys(barData),
|
|
||||||
datasets: [{
|
|
||||||
label: 'Average Response',
|
|
||||||
data: Object.values(barData).map(item => item.average.toFixed(2)),
|
|
||||||
backgroundColor: getRandomColors(Object.keys(barData).length),
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to generate random colors
|
|
||||||
function getRandomColors(count) {
|
|
||||||
const colors = [];
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
colors.push(`rgba(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, 0.2)`);
|
|
||||||
}
|
|
||||||
return colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main function to fetch data and render charts
|
|
||||||
async function main() {
|
|
||||||
try {
|
|
||||||
const responses = await fetchResponses();
|
|
||||||
const questions = {!! json_encode($questions) !!}; // This assumes $questions is passed to the Blade view from Laravel
|
|
||||||
|
|
||||||
const { pieData, barData } = processDataForCharts(responses, questions);
|
|
||||||
renderCharts(pieData, barData);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error processing or rendering charts:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run main function on page load
|
|
||||||
window.addEventListener('DOMContentLoaded', main);
|
|
|
@ -47,14 +47,14 @@
|
||||||
<div style="background-color: #f4f4f9; max-width: 100%" class="question_form p-4 rounded">
|
<div style="background-color: #f4f4f9; max-width: 100%" class="question_form p-4 rounded">
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<div class="question_title_section mb-4">
|
<div class="question_title_section mb-4">
|
||||||
<div class="question_form_top">
|
<div style="border-bottom:5px; border-radius:5px;" class="question_form_top shadow-sm">
|
||||||
<input type="text" id="form-title" name="title" value="{{ $data['title'] ?? '' }}" class="form-control form-control-lg p-2 mb-2" placeholder="Untitled Form" />
|
<input type="text" id="form-title" name="title" value="{{ $data['title'] ?? '' }}" class="form-control form-control-lg p-2 mb-2" placeholder="Untitled Form" />
|
||||||
<input type="text" name="description" id="form-description" value="{{ $data['description'] ?? '' }}" class="form-control form-control-sm" placeholder="Form Description" />
|
<input type="text" name="description" id="form-description" value="{{ $data['description'] ?? '' }}" class="form-control form-control-sm" placeholder="Form Description" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="questions_section">
|
<div class="section" id="questions_section">
|
||||||
<div class="question mb-4 p-4 border rounded bg-white">
|
<div class="question mb-4 p-4 border rounded bg-white shadow-sm">
|
||||||
<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>
|
||||||
|
|
|
@ -6,130 +6,211 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>Edit Form - {{ $form->title }}</title>
|
<title>Edit Form - {{ $form->title }}</title>
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https:
|
||||||
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
|
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https:
|
||||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
<link href="https: <link rel="preconnect" href="https:
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<script src="https:
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
<link rel=" stylesheet" href="https:
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
<link href=" https: rel="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap"
|
< style >
|
||||||
rel="stylesheet">
|
.shadow - custom {
|
||||||
<style>
|
box - shadow: 0 10 px 15 px - 3 px rgba(0, 0, 0, 0.1), 0 4 px 6 px - 2 px rgba(0, 0, 0, 0.05);
|
||||||
.shadow-custom {
|
} <
|
||||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
/style> < /
|
||||||
}
|
head >
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-purple-100">
|
<
|
||||||
<nav class="bg-white p-1 shadow-md">
|
body class = "bg-purple-100" >
|
||||||
<div class="container mx-auto flex justify-between items-center">
|
<
|
||||||
<span style="color: rgb(103,58,183)" class="text-3xl font-bold font-sans"><a href="{{ url('/') }}"
|
nav class = "bg-white p-1 shadow-md" >
|
||||||
style="color: rgb(103,58,183)" class="text-3xl font-bold font-sans">LaraForms</a> - Edit</span>
|
<
|
||||||
<div class="relative dropdown">
|
div class = "container mx-auto flex justify-between items-center" >
|
||||||
<button id="profileMenuButton" class="flex items-center focus:outline-none">
|
<
|
||||||
<img src="{{ asset('images/user.png') }}" alt="Profile"
|
span style = "color: rgb(103,58,183)"
|
||||||
class="w-10 h-10 rounded-full border-2 border-white">
|
class = "text-3xl font-bold font-sans" > < a href = "{{ url('/') }}"
|
||||||
</button>
|
style = "color: rgb(103,58,183)"
|
||||||
<div id="profileMenu"
|
class = "text-3xl font-bold font-sans" > LaraForms < /a> - Edit</span >
|
||||||
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') }}">
|
div class = "relative dropdown" >
|
||||||
@csrf
|
<
|
||||||
<button type="submit"
|
button id = "profileMenuButton"
|
||||||
class="block px-4 py-2 text-gray-700 hover:bg-gray-200 w-full text-left">Logout</button>
|
class = "flex items-center focus:outline-none" >
|
||||||
</form>
|
<
|
||||||
</div>
|
img src = "{{ asset('images/user.png') }}"
|
||||||
</div>
|
alt = "Profile"
|
||||||
</div>
|
class = "w-10 h-10 rounded-full border-2 border-white" >
|
||||||
</nav>
|
<
|
||||||
|
/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 >
|
||||||
|
|
||||||
<div style="max-width: 700px" class="container">
|
<
|
||||||
<form id="edit-form" method="POST" action="{{ route('forms.update', $form) }}"
|
div style = "max-width: 700px"
|
||||||
class="bg-white p-4 rounded shadow-sm">
|
class = "container" >
|
||||||
|
<
|
||||||
|
form id = "edit-form"
|
||||||
|
method = "POST"
|
||||||
|
action = "{{ route('forms.update', $form) }}"
|
||||||
|
class = "bg-white p-4 rounded shadow-sm" >
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
<div class="form-group">
|
<
|
||||||
<input type="text" id="form-title" name="title" class="form-control form-control-lg text-black"
|
div class = "form-group" >
|
||||||
placeholder="Untitled Form" value="{{ $form->title }}" />
|
<
|
||||||
</div>
|
input type = "text"
|
||||||
<div class="form-group">
|
id = "form-title"
|
||||||
<input type="text" name="description" id="form-description"
|
name = "title"
|
||||||
class="form-control form-control-sm text-black" placeholder="Form Description"
|
class = "form-control form-control-lg text-black"
|
||||||
value="{{ $form->description }}" />
|
placeholder = "Untitled Form"
|
||||||
</div>
|
value = "{{ $form->title }}" / >
|
||||||
<div id="questions-section">
|
<
|
||||||
|
/div> <
|
||||||
|
div class = "form-group" >
|
||||||
|
<
|
||||||
|
input type = "text"
|
||||||
|
name = "description"
|
||||||
|
id = "form-description"
|
||||||
|
class = "form-control form-control-sm text-black"
|
||||||
|
placeholder = "Form Description"
|
||||||
|
value = "{{ $form->description }}" / >
|
||||||
|
<
|
||||||
|
/div> <
|
||||||
|
div id = "questions-section" >
|
||||||
@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="form-group">
|
div class = "question mb-4 p-3 border rounded bg-light"
|
||||||
<select class="form-control question-type" id="question-type-{{ $index }}" name="questions[{{ $index }}][type]">
|
data - index = "{{ $index }}" >
|
||||||
<option value="multiple_choice" {{ $question->type === 'multiple_choice' ? 'selected' : '' }}>Multiple Choice</option>
|
<
|
||||||
<option value="checkbox" {{ $question->type === 'checkbox' ? 'selected' : '' }}>Checkbox</option>
|
div class = "form-group" >
|
||||||
<option value="dropdown" {{ $question->type === 'dropdown' ? 'selected' : '' }}>Dropdown</option>
|
<
|
||||||
<option value="text" {{ $question->type === 'text' ? 'selected' : '' }}>Text</option>
|
select class = "form-control question-type"
|
||||||
</select>
|
id = "question-type-{{ $index }}"
|
||||||
</div>
|
name = "questions[{{ $index }}][type]" >
|
||||||
<div class="form-group">
|
<
|
||||||
<input type="text" id="question-text-{{ $index }}"
|
option value = "multiple_choice"
|
||||||
name="questions[{{ $index }}][text]" class="form-control question-input"
|
{{ $question->type === 'multiple_choice' ? 'selected' : '' }} > Multiple Choice < /option> <
|
||||||
value="{{ $question->question_text }}" required>
|
option value = "checkbox"
|
||||||
</div>
|
{{ $question->type === 'checkbox' ? 'selected' : '' }} > Checkbox < /option> <
|
||||||
<div class="form-group form-check">
|
option value = "dropdown"
|
||||||
<input type="checkbox" id="question-required-{{ $index }}"
|
{{ $question->type === 'dropdown' ? 'selected' : '' }} > Dropdown < /option> <
|
||||||
name="questions[{{ $index }}][required]" class="form-check-input"
|
option value = "text"
|
||||||
{{ $question->required ? 'checked' : '' }}>
|
{{ $question->type === 'text' ? 'selected' : '' }} > Text < /option> < /
|
||||||
<label for="question-required-{{ $index }}" class="form-check-label">Required</label>
|
select > <
|
||||||
</div>
|
/div> <
|
||||||
<div class="form-group options-container" style="{{ $question->type === 'text' ? 'display:none;' : '' }}">
|
div class = "form-group" >
|
||||||
<label>Options</label>
|
<
|
||||||
|
input type = "text"
|
||||||
|
id = "question-text-{{ $index }}"
|
||||||
|
name = "questions[{{ $index }}][text]"
|
||||||
|
class = "form-control question-input"
|
||||||
|
value = "{{ $question->question_text }}"
|
||||||
|
required >
|
||||||
|
<
|
||||||
|
/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"
|
||||||
|
style = "{{ $question->type === 'text' ? 'display:none;' : '' }}" >
|
||||||
|
<
|
||||||
|
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">
|
<
|
||||||
<input type="text" name="questions[{{ $index }}][options][{{ $optionIndex }}]" class="form-control option-input" value="{{ $option }}">
|
div class = "option d-flex align-items-center mb-2" >
|
||||||
<span class="delete-option ml-2 text-danger" onclick="deleteOption(this)" style="cursor: pointer;">✕</span>
|
<
|
||||||
|
input type = "text"
|
||||||
|
name = "questions[{{ $index }}][options][{{ $optionIndex }}]"
|
||||||
|
class = "form-control option-input"
|
||||||
|
value = "{{ $option }}" >
|
||||||
|
<
|
||||||
|
span class = "delete-option ml-2 text-danger"
|
||||||
|
onclick = "deleteOption(this)"
|
||||||
|
style = "cursor: pointer;" > & #10005;</span>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
<button type="button" class="btn btn-secondary" onclick="addOption(this)">Add Option</button>
|
<button type= "button"
|
||||||
<button class="btn btn-md" id="moveUpButton" onclick="deleteQuestion(this);">
|
class = "btn btn-secondary"
|
||||||
<img src="{{ asset('images/bin.png') }}" alt="" width="20px" height="20px" />
|
onclick = "addOption(this)" > Add Option < /button> <
|
||||||
</button>
|
button class = "btn btn-md"
|
||||||
</div>
|
id = "moveUpButton"
|
||||||
</div>
|
onclick = "deleteQuestion(this);" >
|
||||||
@endforeach
|
<
|
||||||
<div class="sidebar">
|
img src = "{{ asset('images/bin.png') }}"
|
||||||
<div id="moveableDiv">
|
alt = ""
|
||||||
<button class="btn btn-light shadow-sm" type="button" onclick="addNewQuestion();">
|
width = "20px"
|
||||||
<img src="{{ asset('images/add.png') }}" alt="ADD" width="20px" height="20px" />
|
height = "20px" / >
|
||||||
</button>
|
<
|
||||||
</div>
|
/button> < /
|
||||||
</div>
|
div > <
|
||||||
</div>
|
/div>
|
||||||
<button type="submit" class="btn btn-success mb-4">Save</button>
|
@endforeach <
|
||||||
</form>
|
div class = "sidebar" >
|
||||||
</div>
|
<
|
||||||
|
div id = "moveableDiv" >
|
||||||
|
<
|
||||||
|
button class = "btn btn-light shadow-sm"
|
||||||
|
type = "button"
|
||||||
|
onclick = "addNewQuestion();" >
|
||||||
|
<
|
||||||
|
img src = "{{ asset('images/add.png') }}"
|
||||||
|
alt = "ADD"
|
||||||
|
width = "20px"
|
||||||
|
height = "20px" / >
|
||||||
|
<
|
||||||
|
/button> < /
|
||||||
|
div > <
|
||||||
|
/div> < /
|
||||||
|
div > <
|
||||||
|
button type = "submit"
|
||||||
|
class = "btn btn-success mb-4" > Save < /button> < /
|
||||||
|
form > <
|
||||||
|
/div>
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
|
<
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
script src = "https: <
|
||||||
<script>
|
script src = "https: <
|
||||||
|
script >
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function() {
|
||||||
$('#edit-form').on('submit', function (e) {
|
$('#edit-form').on('submit', function(e) {
|
||||||
e.preventDefault(); // Prevent the default form submission
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
||||||
// Get the form action and data
|
|
||||||
var form = $(this);
|
var form = $(this);
|
||||||
var url = form.attr('action');
|
var url = form.attr('action');
|
||||||
var formData = form.serialize();
|
var formData = form.serialize();
|
||||||
|
|
||||||
// Send an AJAX request to submit the form data
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: url,
|
url: url,
|
||||||
data: formData,
|
data: formData,
|
||||||
success: function (response) {
|
success: function(response) {
|
||||||
// Show SweetAlert on success
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Success!',
|
title: 'Success!',
|
||||||
text: 'Form edited successfully.',
|
text: 'Form edited successfully.',
|
||||||
|
@ -137,13 +218,14 @@ $(document).ready(function () {
|
||||||
confirmButtonText: 'OK'
|
confirmButtonText: 'OK'
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
// Redirect to the show page
|
|
||||||
window.location.href = "{{ route('forms.show', $form) }}";
|
window.location.href =
|
||||||
|
"{{ route('forms.show', $form) }}";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function(xhr, status, error) {
|
||||||
// Handle any errors
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Error!',
|
title: 'Error!',
|
||||||
text: 'An error occurred while editing the form. Please try again.',
|
text: 'An error occurred while editing the form. Please try again.',
|
||||||
|
@ -227,8 +309,10 @@ $(document).ready(function () {
|
||||||
$(element).find('.question-input').attr('id', `question-text-${index}`);
|
$(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('name', `questions[${index}][required]`);
|
||||||
$(element).find('.form-check-input').attr('id', `question-required-${index}`);
|
$(element).find('.form-check-input').attr('id', `question-required-${index}`);
|
||||||
$(element).find('.options-container').find('.option-input').each((optionIndex, optionElement) => {
|
$(element).find('.options-container').find('.option-input').each((optionIndex,
|
||||||
$(optionElement).attr('name', `questions[${index}][options][${optionIndex}]`);
|
optionElement) => {
|
||||||
|
$(optionElement).attr('name',
|
||||||
|
`questions[${index}][options][${optionIndex}]`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -268,12 +352,12 @@ $(document).ready(function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function() {
|
||||||
$('#profileMenuButton').click(function () {
|
$('#profileMenuButton').click(function() {
|
||||||
$('#profileMenu').toggleClass('hidden');
|
$('#profileMenu').toggleClass('hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).click(function (event) {
|
$(document).click(function(event) {
|
||||||
if (!$(event.target).closest('#profileMenuButton, #profileMenu').length) {
|
if (!$(event.target).closest('#profileMenuButton, #profileMenu').length) {
|
||||||
$('#profileMenu').addClass('hidden');
|
$('#profileMenu').addClass('hidden');
|
||||||
}
|
}
|
||||||
|
@ -289,11 +373,3 @@ $(document).ready(function () {
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,176 +1,4 @@
|
||||||
{{-- <!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Forms</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
|
||||||
<link href="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css" rel="stylesheet" />
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
|
||||||
<style>
|
|
||||||
.dropdown:hover .dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow-custom {
|
|
||||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-gray-100">
|
|
||||||
<nav class="bg-white p-4 shadow-lg">
|
|
||||||
<div class="container 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>
|
|
||||||
@if (session('success'))
|
|
||||||
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-2 rounded relative mt-4" role="alert">
|
|
||||||
<span class="block sm:inline">{{ session('success') }}</span>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@if (session('delete'))
|
|
||||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-2 rounded relative mt-4" role="alert">
|
|
||||||
<span class="block sm:inline">{{ session('delete') }}</span>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
<div class="container mx-auto mt-10 ">
|
|
||||||
<div class="flex justify-between mb-6 items-center grid grid-cols-4 gap-20">
|
|
||||||
<a href="{{ route('forms.create') }}"
|
|
||||||
class="inline-block px-6 py-3 text-white font-semibold rounded-md shadow bg-purple-700 hover:bg-purple-900 transition duration-200">Start
|
|
||||||
a new form</a>
|
|
||||||
|
|
||||||
<a style="color: rgb(103,58,183)" class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow">
|
|
||||||
|
|
||||||
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Forms Created</h5>
|
|
||||||
<p class="font-normal text-gray-700 dark:text-gray-400">{{ $totalForms }}</p>
|
|
||||||
</a>
|
|
||||||
<a class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow">
|
|
||||||
|
|
||||||
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Forms Published</h5>
|
|
||||||
<p class="font-normal text-gray-700 dark:text-gray-400">{{ $publishedForms }}</p>
|
|
||||||
</a>
|
|
||||||
<a class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow">
|
|
||||||
|
|
||||||
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Responses Received</h5>
|
|
||||||
<p class="font-normal text-gray-700 dark:text-gray-400">{{ $totalResponses }}</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<h2 class="text-3xl font-semibold text-gray-800 font-sans">Recent Forms</h2>
|
|
||||||
<br>
|
|
||||||
<div class="shadow-custom rounded-lg p-6 bg-gray-100">
|
|
||||||
@if ($forms->isEmpty())
|
|
||||||
<p class="text-gray-600 text-center">No forms available.</p>
|
|
||||||
@else
|
|
||||||
<table class="min-w-full bg-white rounded-md overflow-hidden">
|
|
||||||
<thead class="bg-gray-100">
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
|
||||||
Form Title</th>
|
|
||||||
<th
|
|
||||||
class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
|
||||||
Created At</th>
|
|
||||||
<th
|
|
||||||
class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
|
||||||
Responses</th>
|
|
||||||
<th class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
|
||||||
Status</th>
|
|
||||||
<th class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600"></th>
|
|
||||||
<th class="py-4 px-6 border-b border-gray-200 text-left text-sm font-semibold text-gray-600">
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach ($forms as $form)
|
|
||||||
<tr class="hover:bg-gray-50 transition duration-150">
|
|
||||||
<td class="py-4 px-6 border-b border-gray-200">
|
|
||||||
<a href="{{ route('forms.show', $form) }}"
|
|
||||||
class="text-blue-600 font-semibold hover:underline">{{ $form->title }}</a>
|
|
||||||
<p class="text-gray-600">{{ $form->description }}</p>
|
|
||||||
</td>
|
|
||||||
<td class="py-4 px-6 border-b border-gray-200">{{ $form->created_at->format('M d, Y') }}
|
|
||||||
</td>
|
|
||||||
<td class="py-4 px-6 border-b border-gray-200">
|
|
||||||
<a href="{{ route('responses.viewResponses', $form) }}"
|
|
||||||
class="text-blue-500 hover:underline">View Responses</a>
|
|
||||||
</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">
|
|
||||||
@if (!$form->is_published)
|
|
||||||
<a href="{{ route('forms.edit', $form) }}" class="text-green-500 hover:underline">Edit</a>
|
|
||||||
@else
|
|
||||||
<a href="#" class="text-gray-500" id="formd" onclick="handle()">Edit</a>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<form action="{{ route('forms.destroy', $form) }}" method="POST"
|
|
||||||
class="inline-block">
|
|
||||||
@csrf
|
|
||||||
@method('DELETE')
|
|
||||||
<button type="submit" class="text-red-500 hover:underline">Delete</button>
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function handle() {
|
|
||||||
Swal.fire({
|
|
||||||
title: 'You cannot edit a published form',
|
|
||||||
icon: 'info',
|
|
||||||
confirmButtonText: 'OK'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setTimeout(function() {
|
|
||||||
var successMessage = document.getElementById('successMessage');
|
|
||||||
if (successMessage) {
|
|
||||||
successMessage.remove();
|
|
||||||
}
|
|
||||||
}, 3000);
|
|
||||||
</script>
|
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js" ></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
--}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
@ -230,21 +58,24 @@
|
||||||
class="inline-block px-6 py-3 text-white font-semibold rounded-md shadow bg-purple-700 hover:bg-purple-900 transition duration-200">Start
|
class="inline-block px-6 py-3 text-white font-semibold rounded-md shadow bg-purple-700 hover:bg-purple-900 transition duration-200">Start
|
||||||
a new form</a>
|
a new form</a>
|
||||||
|
|
||||||
<a href="{{ route('forms.template', 'contact') }}" style="color: rgb(103,58,183)"
|
<a style="color: rgb(103,58,183)" class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow">
|
||||||
class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-50 transition duration-200">
|
|
||||||
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Contact Information</h5>
|
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Forms Created</h5>
|
||||||
<p class="font-normal text-gray-700 dark:text-gray-400">Use this template to create a contact information form.</p>
|
<p class="font-normal text-gray-700 dark:text-gray-400">{{ $totalForms }}</p>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('forms.template', 'rsvp') }}" class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-50 transition duration-200">
|
<a class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow">
|
||||||
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">RSVP</h5>
|
|
||||||
<p class="font-normal text-gray-700 dark:text-gray-400">Use this template to create an RSVP form for events.</p>
|
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Forms Published</h5>
|
||||||
|
<p class="font-normal text-gray-700 dark:text-gray-400">{{ $publishedForms }}</p>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('forms.template', 'party') }}" class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow hover:bg-gray-50 transition duration-200">
|
<a class="block max-w-md p-5 bg-white border border-gray-200 rounded-lg shadow">
|
||||||
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Party Invite</h5>
|
|
||||||
<p class="font-normal text-gray-700 dark:text-gray-400">Use this template to create a party invite form.</p>
|
<h5 class="mb-2 text-gray-800 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Total Responses Received</h5>
|
||||||
|
<p class="font-normal text-gray-700 dark:text-gray-400">{{ $totalResponses }}</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<hr style="height:30px">
|
<hr>
|
||||||
|
<br>
|
||||||
<h2 class="text-3xl font-semibold text-gray-800 font-sans">Recent Forms</h2>
|
<h2 class="text-3xl font-semibold text-gray-800 font-sans">Recent Forms</h2>
|
||||||
<br>
|
<br>
|
||||||
<div class="shadow-custom rounded-lg p-6 bg-gray-100">
|
<div class="shadow-custom rounded-lg p-6 bg-gray-100">
|
||||||
|
|
|
@ -1,42 +1,3 @@
|
||||||
{{-- <!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<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=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900&display=swap" rel="stylesheet">
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<title>Responses</title>
|
|
||||||
<link rel="stylesheet" href="{{ asset('css/index.css') }}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="form_header roboto-light">
|
|
||||||
<div class="form_header_left">
|
|
||||||
<a href="/forms"><img src="{{ asset('images/google-form.png') }}" class="form_header_icon" height="45px" width="40px" /></a>
|
|
||||||
<h1 class="form_name">{{ $form->title }} - Responses</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<div class="responses_list">
|
|
||||||
@if ($responses->isEmpty())
|
|
||||||
<p>No responses available.</p>
|
|
||||||
@else
|
|
||||||
<ul>
|
|
||||||
@foreach ($responses as $response)
|
|
||||||
<li>
|
|
||||||
<a href="{{ route('forms.responses.show', [$form, $response]) }}">Response from {{ $response->user->name ?? 'Anonymous' }} - {{ $response->submitted_at }}</a>
|
|
||||||
</li>
|
|
||||||
@endforeach
|
|
||||||
</ul>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script src="{{ asset('js/script.js') }}"></script>
|
|
||||||
</body>
|
|
||||||
</html> --}}
|
|
||||||
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
|
|
|
@ -1,108 +1,3 @@
|
||||||
{{-- @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'
|
|
||||||
}).then()=>{
|
|
||||||
window.location.href
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@endsection --}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@extends('layouts.app')
|
@extends('layouts.app')
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
<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>
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<a href="/forms" class="d-flex align-items-center">
|
<a href="/forms" class="d-flex align-items-center">
|
||||||
<img src="{{ asset('images/google-form.png') }}" alt="Google Form Icon" height="40px" width="40px" />
|
<img src="{{ asset('images/google-form.png') }}" alt="Google Form Icon" height="40px" width="40px" />
|
||||||
</a>
|
</a>
|
||||||
<h2 style="color: rgb(103,58,183)" class="ml-3">{{ $form->title }} - Response Detail</h2>
|
<h4 style="color: rgb(103,58,183)" class="ml-3">{{ $form->title }} - Response Detail</h4>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue