Added flash messages, minor UI changes
This commit is contained in:
parent
03da2ae482
commit
6bc022b0f3
|
@ -8,7 +8,7 @@ use App\Models\Question;
|
|||
use App\Models\Response;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use Illuminate\Support\Facades\Session;
|
||||
class FormController extends Controller
|
||||
{
|
||||
public function index()
|
||||
|
@ -64,7 +64,7 @@ return view('forms.edit', compact('form', 'questions'));
|
|||
|
||||
$question->save();
|
||||
}
|
||||
|
||||
Session::flash('success', 'Form created successfully!');
|
||||
return response()->json(['success' => true, 'form_id' => $form->id]);
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,12 @@ return view('forms.edit', compact('form', 'questions'));
|
|||
return view('forms.show', compact('form'));
|
||||
}
|
||||
|
||||
public function preview($id)
|
||||
{
|
||||
$form = Form::findOrFail($id);
|
||||
return view('forms.previewForm', compact('form'));
|
||||
}
|
||||
|
||||
|
||||
public function update(Request $request, Form $form)
|
||||
{
|
||||
|
@ -147,6 +153,6 @@ return view('forms.edit', compact('form', 'questions'));
|
|||
// This will also delete all related questions and responses due to foreign key constraints
|
||||
$form->delete();
|
||||
|
||||
return redirect()->route('forms.index')->with('success', 'Form deleted successfully.');
|
||||
return redirect()->route('forms.index')->with('delete', 'Form deleted successfully.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ public function viewResponses(Form $form)
|
|||
public function showForm(Form $form)
|
||||
{
|
||||
$questions = $form->questions;
|
||||
if (!$form->is_published) {
|
||||
return redirect('/forms')->with('delete', 'This form is not published.');
|
||||
}
|
||||
|
||||
return view('responses.showForm', compact('form', 'questions'));
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"sweetalert": "^2.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"axios": "^1.6.4",
|
||||
|
@ -723,6 +726,11 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-object-assign": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
|
||||
"integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw=="
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
|
@ -994,6 +1002,11 @@
|
|||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/promise-polyfill": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz",
|
||||
"integrity": "sha512-g0LWaH0gFsxovsU7R5LrrhHhWAWiHRnh1GPrhXnPgYsDkIqjRYUYSZEsej/wtleDrz5xVSIDbeKfidztp2XHFQ=="
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
|
@ -1073,6 +1086,15 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sweetalert": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.2.tgz",
|
||||
"integrity": "sha512-iWx7X4anRBNDa/a+AdTmvAzQtkN1+s4j/JJRWlHpYE8Qimkohs8/XnFcWeYHH2lMA8LRCa5tj2d244If3S/hzA==",
|
||||
"dependencies": {
|
||||
"es6-object-assign": "^1.1.0",
|
||||
"promise-polyfill": "^6.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
|
|
|
@ -12,5 +12,8 @@
|
|||
"laravel-vite-plugin": "^1.0.0",
|
||||
"sass": "^1.56.1",
|
||||
"vite": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"sweetalert": "^2.1.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
top: 0;
|
||||
left: 75%;
|
||||
top: 10%;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btnp {
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
body {
|
||||
body {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
background-color: #f2f2f2;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.form_header {
|
||||
}
|
||||
.form_header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: white;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.form_header_left {
|
||||
}
|
||||
.form_header_left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.form_header_icon {
|
||||
}
|
||||
.form_header_icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.form_header_right {
|
||||
}
|
||||
.form_header_right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.form_header_right img {
|
||||
}
|
||||
.form_header_right img {
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.container {
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 20px auto;
|
||||
background-color: white;
|
||||
|
@ -36,39 +36,39 @@ body {
|
|||
border-left: 4px #4285f4 solid;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.start_form {
|
||||
}
|
||||
.start_form {
|
||||
margin-bottom: 10px;
|
||||
background-color: #f5f5f5;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.start_form a {
|
||||
}
|
||||
.start_form a {
|
||||
text-decoration: none;
|
||||
color: rgb(103, 58, 183);
|
||||
}
|
||||
.start_form a:hover {
|
||||
}
|
||||
.start_form a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.recent_forms {
|
||||
}
|
||||
.recent_forms {
|
||||
background-color: #f4f4f9;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.recent_forms h2 {
|
||||
}
|
||||
.recent_forms h2 {
|
||||
color: rgb(103, 58, 183);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.recent_forms ul {
|
||||
}
|
||||
.recent_forms ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
.recent_forms ul li {
|
||||
}
|
||||
.recent_forms ul li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.recent_forms ul li a {
|
||||
}
|
||||
.recent_forms ul li a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
|
@ -76,15 +76,29 @@ body {
|
|||
border-radius: 4px;
|
||||
background-color: #e0e0e0;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
.recent_forms ul li a:hover {
|
||||
}
|
||||
.recent_forms ul li a:hover {
|
||||
background-color: #c5c5c5;
|
||||
}
|
||||
.form_name {
|
||||
color: #5f6368;
|
||||
}
|
||||
.roboto-light {
|
||||
}
|
||||
.form_name {
|
||||
color: black;
|
||||
font-weight: 500;
|
||||
}
|
||||
.roboto-light {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 150;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
#shareLink{
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.btn-primary{
|
||||
background-color: rgb(103, 58, 183);
|
||||
}
|
||||
|
||||
:hover.btn-primary{
|
||||
background-color: rgb(96, 4, 96);
|
||||
color: white;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
.form_preview {
|
||||
padding: 20px;
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
background-color: #f4f4f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#form_name {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 32px;
|
||||
font-weight: 400;
|
||||
line-height: 135%;
|
||||
border-bottom: 1px solid #f4f4f9;
|
||||
color: black;
|
||||
}
|
||||
|
||||
#form_desc {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
line-height: 100%;
|
||||
border-bottom: 1px solid #f4f4f9;
|
||||
color: black;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.question {
|
||||
margin-bottom: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
border-top: 8px solid rgb(103, 58, 183);
|
||||
}
|
||||
|
||||
.question_title {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.options {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.option {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.option input[type="radio"],
|
||||
.option input[type="checkbox"] {
|
||||
margin-right: 10px;
|
||||
}
|
|
@ -48,7 +48,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
</div>
|
||||
<button class="btn btn-secondary" onclick="addOption(this)">Add Option</button>
|
||||
<button class="btnn" onclick="deleteQuestion(this)">
|
||||
<img src={{asset("images/bin.png")}} alt="" width="20px" height="20px" />
|
||||
<img src={{ asset('images/bin.png') }} alt="" width="20px" height="20px" />
|
||||
</button>
|
||||
`;
|
||||
questionsSection.appendChild(newQuestionDiv);
|
||||
|
@ -133,7 +133,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
window.changeQuestionType = changeQuestionType;
|
||||
window.saveForm = saveForm;
|
||||
|
||||
window.previewForm = function () {
|
||||
window.previewForm = function (formId) {
|
||||
const formTitle = document.getElementById("form-title").value;
|
||||
const formDescription =
|
||||
document.getElementById("form-description").value;
|
||||
|
@ -160,7 +160,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
data: JSON.stringify(formData),
|
||||
});
|
||||
|
||||
window.open(`preview.html?${formParams.toString()}`, "_blank");
|
||||
window.location.href = '/forms/' + formId + '/preview';
|
||||
};
|
||||
|
||||
window.addNewQuestion = addNewQuestion;
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="question_form">
|
||||
<div style="background-color: #f0ebf8" class="question_form">
|
||||
<br />
|
||||
<div class="section">
|
||||
<div class="question_title_section">
|
||||
|
@ -92,14 +92,14 @@
|
|||
</div>
|
||||
<div class="sidebar">
|
||||
<div id="moveableDiv">
|
||||
<button class="btnp" onclick="addNewQuestion(); moveDown()">
|
||||
<button style="background-color: white"class="btnp" onclick="addNewQuestion(); moveDown()">
|
||||
<img src={{ asset('images/add.png') }} alt="" width="20px" height="20px" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnsub">
|
||||
<div style="background-color: #f0ebf8"class="btnsub">
|
||||
<span>
|
||||
<button type="submit" name="save" value="save" onclick="saveForm()"
|
||||
class="btnsave btn btn-secondary">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
@ -9,20 +10,25 @@
|
|||
.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-50">
|
||||
|
||||
<body style="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>
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
|
@ -33,10 +39,21 @@
|
|||
</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">
|
||||
<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 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>
|
||||
|
||||
</div>
|
||||
<h2 class="text-3xl font-semibold text-gray-800 font-sans">Recent Forms</h2>
|
||||
|
@ -48,30 +65,41 @@
|
|||
<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">Actions</th>
|
||||
<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">
|
||||
Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($forms as $form)
|
||||
@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>
|
||||
<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">{{ $form->created_at->format('M d, Y') }}
|
||||
</td>
|
||||
<td class="py-4 px-6 border-b border-gray-200">
|
||||
@if ($form->is_published)
|
||||
<a href="{{ route('responses.viewResponses', $form) }}" class="text-blue-500 hover:underline">View Responses</a>
|
||||
@else
|
||||
<span class="text-gray-600">Not Published</span>
|
||||
@endif
|
||||
<a href="{{ route('responses.viewResponses', $form) }}"
|
||||
class="text-blue-500 hover:underline">View Responses</a>
|
||||
</td>
|
||||
<td class="py-8 px-6 border-b border-gray-200 flex items-center space-x-10">
|
||||
<a href="{{ route('forms.edit', $form) }}" class="text-green-500 hover:underline">Edit</a>
|
||||
<form action="{{ route('forms.destroy', $form) }}" method="POST" class="inline-block">
|
||||
@if (!$form->is_published)
|
||||
<a href="{{ route('forms.edit', $form) }}"
|
||||
class="text-green-500 hover:underline">Edit</a>
|
||||
@endif
|
||||
<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>
|
||||
|
@ -89,13 +117,13 @@
|
|||
document.getElementById('profileMenuButton').addEventListener('click', function() {
|
||||
document.getElementById('profileMenu').classList.toggle('hidden');
|
||||
});
|
||||
setTimeout(function() {
|
||||
var successMessage = document.getElementById('successMessage');
|
||||
if (successMessage) {
|
||||
successMessage.remove();
|
||||
}
|
||||
}, 3000);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Form Preview</title>
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{asset("css/preview.css")}}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="form_preview">
|
||||
<h1 id="form_name"></h1>
|
||||
<p id="form_desc"></p>
|
||||
<div id="questions_container"></div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const formName = document.getElementById('form_name');
|
||||
const formDesc = document.getElementById('form_desc');
|
||||
const questionsContainer = document.getElementById('questions_container');
|
||||
|
||||
function getParameterByName(name, url = window.location.href) {
|
||||
name = name.replace(/[\[\]]/g, '\\$&');
|
||||
const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`),
|
||||
results = regex.exec(url);
|
||||
if (!results) return null;
|
||||
if (!results[2]) return '';
|
||||
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
const formTitle = getParameterByName('title');
|
||||
const formDescription = getParameterByName('description');
|
||||
const formData = JSON.parse(getParameterByName('data'));
|
||||
|
||||
formName.textContent = formTitle;
|
||||
formDesc.textContent = formDescription;
|
||||
|
||||
formData.forEach((question, index) => {
|
||||
const questionType = question.type;
|
||||
const questionText = question.text;
|
||||
const options = question.options;
|
||||
|
||||
let questionHtml = `<div class="question"><h3 class="question_title">${questionText}</h3><div class="options">`;
|
||||
|
||||
options.forEach(option => {
|
||||
if (questionType === 'multiple_choice') {
|
||||
questionHtml += `<div class="option"><input type="radio" name="q${index}">${option}</div>`;
|
||||
} else if (questionType === 'checkbox') {
|
||||
questionHtml += `<div class="option"><input type="checkbox" name="q${index}">${option}</div>`;
|
||||
} else if (questionType === 'dropdown') {
|
||||
if (option === options[0]) questionHtml += `<select class="form-control">`;
|
||||
questionHtml += `<option>${option}</option>`;
|
||||
if (option === options[options.length - 1]) questionHtml += `</select>`;
|
||||
}
|
||||
});
|
||||
|
||||
questionHtml += `</div></div>`;
|
||||
questionsContainer.innerHTML += questionHtml;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -17,9 +17,9 @@
|
|||
<!-- Scripts -->
|
||||
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
|
||||
</head>
|
||||
<body>
|
||||
<body style="background-color: #f0ebf8">
|
||||
<div id="app">
|
||||
<nav class="navbar navbar-expand-md navbar-light shadow-sm" style="background-color: rgb(103,58,183)">
|
||||
<nav class="navbar navbar-expand-md navbar-light shadow-md px-4 py-3 flex justify-between items-center" style="background-color: rgb(103,58,183)">
|
||||
<div class="container">
|
||||
<a class="navbar-brand text-white" href="{{ url('/') }}">
|
||||
{{ config('app.name', 'Laravel') }}
|
||||
|
|
|
@ -1,51 +1,5 @@
|
|||
{{-- @extends('layouts.app')
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<h1>{{ $form->title }}</h1>
|
||||
<p>{{ $form->description }}</p>
|
||||
|
||||
<form action="{{ route('responses.submitForm', $form) }}" method="POST">
|
||||
@csrf
|
||||
@foreach ($questions as $question)
|
||||
<div class="form-group">
|
||||
<label>{{ $question->question_text }}</label>
|
||||
@if ($question->type == 'multiple_choice')
|
||||
@foreach (json_decode($question->options) as $option)
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="answers[{{ $question->id }}]"
|
||||
value="{{ $option }}">
|
||||
<label class="form-check-label">{{ $option }}</label>
|
||||
</div>
|
||||
@endforeach
|
||||
@elseif($question->type == 'checkbox')
|
||||
@foreach (json_decode($question->options) as $option)
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="answers[{{ $question->id }}][]"
|
||||
value="{{ $option }}">
|
||||
<label class="form-check-label">{{ $option }}</label>
|
||||
</div>
|
||||
@endforeach
|
||||
@elseif($question->type == 'dropdown')
|
||||
<select class="form-control" name="answers[{{ $question->id }}]">
|
||||
@foreach (json_decode($question->options) as $option)
|
||||
<option value="{{ $option }}">{{ $option }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<button type="submit" class="focus:outline-none text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-sm px-5 py-2.5 mb-2 dark:bg-purple-600 dark:hover:bg-purple-700 dark:focus:ring-purple-900"">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
@endsection --}}
|
||||
|
||||
|
||||
@extends('layouts.app')
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
|
||||
@section('content')
|
||||
<div class="container mx-auto py-8">
|
||||
|
@ -91,4 +45,53 @@
|
|||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
--}}
|
||||
|
||||
|
||||
@extends('layouts.app')
|
||||
@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 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 == 'short_answer')
|
||||
<input type="text" name="answers[{{ $question->id }}]" class="form-input mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm">
|
||||
@elseif($question->type == 'long_answer')
|
||||
<textarea name="answers[{{ $question->id }}]" class="form-textarea mt-2 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm"></textarea>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
<button type="submit" class="mt-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>
|
||||
@endsection
|
||||
|
|
|
@ -4,45 +4,61 @@
|
|||
<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">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;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>Response Detail</title>
|
||||
<link rel="stylesheet" href="{{ asset('css/index.css') }}">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</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 }} - Response Detail</h1>
|
||||
<body class="bg-gray-50 font-roboto">
|
||||
<div class="bg-white shadow-md p-4 flex justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<a href="/forms">
|
||||
<img src="{{ asset('images/google-form.png') }}" class="h-12 w-12 mr-4" alt="Google Form Icon" />
|
||||
</a>
|
||||
<h1 class="text-xl font-semibold">{{ $form->title }} - Response Detail</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="response_detail">
|
||||
<h2>Response from {{ $responses->first()->user->name ?? 'Anonymous' }} - {{ $responses->first()->submitted_at }}</h2>
|
||||
|
||||
<div class="container mx-auto mt-8">
|
||||
<div class="bg-white p-6 shadow-md rounded-lg">
|
||||
<h2 class="text-2xl font-bold mb-4">Response from {{ $responses->first()->user->name ?? 'Anonymous' }} - {{ $responses->first()->submitted_at }}</h2>
|
||||
|
||||
@foreach ($responses as $response)
|
||||
@php
|
||||
$question = $questions[$response->question_id];
|
||||
$question = $questions[$response->question_id] ?? null;
|
||||
$decodedAnswers = json_decode($response->answers, true);
|
||||
@endphp
|
||||
<div class="question">
|
||||
<h3>{{ $question->question_text }}</h3>
|
||||
@if ($question->type == 'multiple_choice' || $question->type == 'checkbox' || $question->type == 'dropdown')
|
||||
|
||||
@if ($question)
|
||||
<div class="mb-6">
|
||||
<h3 class="text-lg font-medium">{{ $question->question_text }}</h3>
|
||||
@if ($question->type == 'dropdown')
|
||||
<select disabled class="w-full p-2 mt-2 border rounded">
|
||||
@foreach (json_decode($question->options) as $option)
|
||||
<p>
|
||||
<input type="radio" disabled {{ in_array($option, (array)$decodedAnswers) ? 'checked' : '' }}>
|
||||
<option {{ ($option == $decodedAnswers) ? 'selected' : '' }}>
|
||||
{{ $option }}
|
||||
</p>
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@elseif (in_array($question->type, ['multiple_choice', 'checkbox']))
|
||||
<div class="mt-2">
|
||||
@foreach (json_decode($question->options) as $option)
|
||||
<label class="block">
|
||||
<input type="{{ $question->type == 'checkbox' ? 'checkbox' : 'radio' }}" disabled {{ in_array($option, (array)$decodedAnswers) ? 'checked' : '' }} class="mr-2">
|
||||
{{ $option }}
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p>{{ is_array($decodedAnswers) ? implode(', ', $decodedAnswers) : $decodedAnswers }}</p>
|
||||
<p class="mt-2 p-2 bg-gray-100 rounded">{{ is_array($decodedAnswers) ? implode(', ', $decodedAnswers) : $decodedAnswers }}</p>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<p class="text-red-500">Question not found for ID: {{ $response->question_id }}</p>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
@ -59,28 +75,29 @@
|
|||
<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">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;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>Response Detail</title>
|
||||
<link rel="stylesheet" href="{{ asset('css/index.css') }}">
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</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 }} - Response Detail</h1>
|
||||
<body style="background-color: #f0ebf8" class="font-roboto">
|
||||
<header class="bg-white shadow-md py-4">
|
||||
<div class="container mx-auto flex justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<a href="/forms">
|
||||
<img src="{{ asset('images/google-form.png') }}" class="h-12 w-12 mr-4" alt="Google Form Icon" />
|
||||
</a>
|
||||
<h1 style="color: rgb(103,58,183)" class="text-xl font-semibold">{{ $form->title }} - Response Detail</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="response_detail">
|
||||
<h2>Response from {{ $responses->first()->user->name ?? 'Anonymous' }} - {{ $responses->first()->submitted_at }}</h2>
|
||||
</header>
|
||||
|
||||
<main class="container mx-auto mt-8">
|
||||
<div class="bg-white p-8 shadow-lg rounded-lg">
|
||||
<h2 class="text-2xl font-bold mb-6">Response from {{ $responses->first()->user->name ?? 'Anonymous' }} - {{ $responses->first()->submitted_at }}</h2>
|
||||
|
||||
@foreach ($responses as $response)
|
||||
@php
|
||||
|
@ -89,10 +106,10 @@
|
|||
@endphp
|
||||
|
||||
@if ($question)
|
||||
<div class="question">
|
||||
<h3>{{ $question->question_text }}</h3>
|
||||
<div class="mb-8">
|
||||
<h3 class="text-lg font-medium mb-2">{{ $question->question_text }}</h3>
|
||||
@if ($question->type == 'dropdown')
|
||||
<select disabled>
|
||||
<select disabled class="w-full p-3 border border-gray-600 rounded-lg">
|
||||
@foreach (json_decode($question->options) as $option)
|
||||
<option {{ ($option == $decodedAnswers) ? 'selected' : '' }}>
|
||||
{{ $option }}
|
||||
|
@ -100,25 +117,26 @@
|
|||
@endforeach
|
||||
</select>
|
||||
@elseif (in_array($question->type, ['multiple_choice', 'checkbox']))
|
||||
<div class="space-y-2">
|
||||
@foreach (json_decode($question->options) as $option)
|
||||
<p>
|
||||
<input type="{{ $question->type == 'checkbox' ? 'checkbox' : 'radio' }}" disabled {{ in_array($option, (array)$decodedAnswers) ? 'checked' : '' }}>
|
||||
<label class="block">
|
||||
<input type="{{ $question->type == 'checkbox' ? 'checkbox' : 'radio' }}" disabled {{ in_array($option, (array)$decodedAnswers) ? 'checked' : '' }} class="mr-2">
|
||||
{{ $option }}
|
||||
</p>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p>{{ is_array($decodedAnswers) ? implode(', ', $decodedAnswers) : $decodedAnswers }}</p>
|
||||
<p class="mt-2 p-3 bg-gray-100 rounded-lg">{{ is_array($decodedAnswers) ? implode(', ', $decodedAnswers) : $decodedAnswers }}</p>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<p>Question not found for ID: {{ $response->question_id }}</p>
|
||||
<p class="text-red-500">Question not found for ID: {{ $response->question_id }}</p>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="{{ asset('js/script.js') }}"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
|
|
|
@ -1,57 +1,108 @@
|
|||
<!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>Form Responses</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<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 class="form_header_right">
|
||||
<img src="{{ asset('images/menu.png') }}" alt="menu" height="30px" width="30px" />
|
||||
<img src="{{ asset('images/user.png') }}" alt="" height="30px" width="30px" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h2>Responses</h2>
|
||||
|
||||
<div class="share-link">
|
||||
<input type="text" value="{{ route('responses.showForm', $form) }}" id="shareLink" readonly>
|
||||
<button onclick="copyLink()">Copy Link</button>
|
||||
<body style="background-color: #f0ebf8" class="font-roboto text-gray-800">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="bg-white shadow-md px-6 py-4 flex justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<a href="/forms" class="mr-4">
|
||||
<img src="{{ asset('images/google-form.png') }}" alt="Google Forms" class="h-12 w-auto">
|
||||
</a>
|
||||
<h1 class="text-2xl font-semibold text-purple-900">{{ $form->title }} - Responses</h1>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<img src="{{ asset('images/menu.png') }}" alt="Menu" class="h-8 w-8 mr-4">
|
||||
<img src="{{ asset('images/user.png') }}" alt="User" class="h-8 w-8">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="mx-auto max-w-7xl px-6 py-8">
|
||||
|
||||
<!-- Share Link -->
|
||||
<div class="flex items-center mb-6">
|
||||
<h2 class="text-xl font-semibold mr-4">Responses</h2>
|
||||
<div class="flex items-center">
|
||||
<input type="text" value="{{ route('responses.showForm', $form) }}" id="shareLink"
|
||||
class="bg-white border border-gray-300 px-3 py-1 rounded-l sm:w-auto focus:outline-none"
|
||||
readonly>
|
||||
|
||||
<button onclick="copyLink()"
|
||||
class="bg-purple-600 text-white px-4 py-1.5 rounded-r hover:bg-purple-700 focus:outline-none ml-2 sm:ml-0 mt-2 sm:mt-0">
|
||||
Copy Link
|
||||
</button>
|
||||
<!-- Copy Link Notification -->
|
||||
<div id="copyNotification"
|
||||
class="hidden bg-green-100 border border-green-500 text-green-700 px-3 py-2 rounded ml-2">
|
||||
Link copied!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Responses Table -->
|
||||
@if ($responses->isEmpty())
|
||||
<p class="text-gray-600">No responses available.</p>
|
||||
@else
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full bg-white shadow-md rounded-lg overflow-hidden">
|
||||
<thead class="bg-gray-200 text-gray-600 text-sm leading-normal">
|
||||
<tr>
|
||||
<th class="py-3 px-6 text-left">User</th>
|
||||
<th class="py-3 px-6 text-left">Submitted At</th>
|
||||
<th class="py-3 px-6 text-left">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-600 text-sm font-light">
|
||||
@foreach ($responses as $responseGroup)
|
||||
<tr class="border-b border-gray-200 hover:bg-gray-100">
|
||||
<td class="py-3 px-6 text-left">
|
||||
{{ $responseGroup->first()->user->name ?? 'Anonymous' }}
|
||||
</td>
|
||||
<td class="py-3 px-6 text-left">
|
||||
{{ $responseGroup->first()->created_at->diffForHumans()}}
|
||||
</td>
|
||||
<td class="py-3 px-6 text-left">
|
||||
<a href="{{ route('responses.viewResponse', ['form' => $form, 'responseId' => $responseGroup->first()->response_id]) }}"
|
||||
target="_blank"
|
||||
class="text-blue-600 hover:text-blue-700 focus:outline-none">View Response</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Script for Copy Link Functionality -->
|
||||
<script>
|
||||
function copyLink() {
|
||||
var copyText = document.getElementById("shareLink");
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 99999); /* For mobile devices */
|
||||
document.execCommand("copy");
|
||||
alert("Link copied: " + copyText.value);
|
||||
|
||||
// Show copy notification next to the copy button
|
||||
var copyNotification = document.getElementById("copyNotification");
|
||||
copyNotification.classList.remove("hidden");
|
||||
setTimeout(function () {
|
||||
copyNotification.classList.add("hidden");
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
|
||||
@if ($responses->isEmpty())
|
||||
<p>No responses available.</p>
|
||||
@else
|
||||
<ul>
|
||||
@foreach ($responses as $responseGroup)
|
||||
<li>
|
||||
User: {{ $responseGroup->first()->user->name ?? 'Anonymous' }} - Submitted at: {{ $responseGroup->first()->submitted_at }}
|
||||
<a href="{{ route('responses.viewResponse', ['form' => $form, 'responseId' => $responseGroup->first()->response_id]) }}" target="_blank">View Response</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</div>
|
||||
<!-- Custom Scripts -->
|
||||
<script src="{{ asset('js/script.js') }}"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -21,6 +21,8 @@ Route::middleware(['auth'])->group(function () {
|
|||
Route::get('/forms/{form}/edit', [FormController::class, 'edit'])->name('forms.edit');
|
||||
Route::put('/forms/{form}', [FormController::class, 'update'])->name('forms.update');
|
||||
Route::delete('/forms/{form}', [FormController::class, 'destroy'])->name('forms.destroy');
|
||||
Route::get('/forms/{form}/preview', [FormController::class, 'preview'])->name('forms.preview');
|
||||
|
||||
});
|
||||
|
||||
// Response routes
|
||||
|
|
Loading…
Reference in New Issue