Code and bug fixes

This commit is contained in:
yash 2024-07-24 11:11:55 +05:30
parent e747614bd3
commit 0d8c522732
12 changed files with 585 additions and 954 deletions

View File

@ -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,7 +91,6 @@ 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;

View File

@ -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');

View File

@ -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;

View File

@ -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;
@ -27,18 +28,18 @@ class ResponseController extends Controller
} }
// 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] = [
@ -62,16 +63,16 @@ class ResponseController extends Controller
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] = [
@ -107,21 +108,21 @@ 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();
@ -150,9 +151,4 @@ 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.');
} }
} }

View File

@ -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;">&#10005;</span> <span class="delete-option ml-2 text-danger" onclick="deleteOption(this)" style="cursor: pointer;">&#10005;</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);
}); });

View File

@ -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);

View File

@ -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>

View File

@ -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"
rel="stylesheet">
< style > < style >
.shadow - custom { .shadow - custom {
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); 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);
} } <
</style> /style> < /
</head> 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 = "text-3xl font-bold font-sans" > < a href = "{{ url('/') }}"
style = "color: rgb(103,58,183)"
class = "text-3xl font-bold font-sans" > LaraForms < /a> - Edit</span >
<
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" > class = "w-10 h-10 rounded-full border-2 border-white" >
</button> <
<div id="profileMenu" /button> <
div id = "profileMenu"
class = "dropdown-menu hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-2" > 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 form method = "POST"
<button type="submit" action = "{{ route('logout') }}" >
class="block px-4 py-2 text-gray-700 hover:bg-gray-200 w-full text-left">Logout</button> @csrf <
</form> button type = "submit"
</div> class = "block px-4 py-2 text-gray-700 hover:bg-gray-200 w-full text-left" > Logout < /button> < /
</div> form > <
</div> /div> < /
</nav> 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 = "container" >
<
form id = "edit-form"
method = "POST"
action = "{{ route('forms.update', $form) }}"
class = "bg-white p-4 rounded shadow-sm" > 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"
placeholder = "Untitled Form"
value = "{{ $form->title }}" / >
<
/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 }}" / > value = "{{ $form->description }}" / >
</div> <
<div id="questions-section"> /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->type === 'text' ? 'selected' : '' }} > Text < /option> < /
select > <
/div> <
div class = "form-group" >
<
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' : '' }} > {{ $question->required ? 'checked' : '' }} >
<label for="question-required-{{ $index }}" class="form-check-label">Required</label> <
</div> label
<div class="form-group options-container" style="{{ $question->type === 'text' ? 'display:none;' : '' }}"> for = "question-required-{{ $index }}"
<label>Options</label> 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;">&#10005;</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}]`);
}); });
}); });
} }
@ -289,11 +373,3 @@ $(document).ready(function () {
</body> </body>
</html> </html>

View File

@ -1,175 +1,3 @@
{{-- <!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> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -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">

View File

@ -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">

View File

@ -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>

View File

@ -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>