From 8ffd88592885dd6ebc7e6613be0144d1aa8acc61 Mon Sep 17 00:00:00 2001 From: Mohit Yadav <79302660+Mohityadav-code@users.noreply.github.com> Date: Fri, 4 Jul 2025 17:38:20 +0530 Subject: [PATCH 1/6] minor important bugs fixed --- form-builder/backend/database.js | 29 ++- form-builder/backend/routes/formRoutes.js | 18 +- form-builder/src/App.jsx | 1 + form-builder/src/FormBuilder.jsx | 216 +++++++++++++++--- form-builder/src/api.js | 16 ++ form-builder/src/components/Dashboard.jsx | 2 +- .../src/components/FormBuilderView.jsx | 4 +- 7 files changed, 248 insertions(+), 38 deletions(-) diff --git a/form-builder/backend/database.js b/form-builder/backend/database.js index 3cc0910..4889a0f 100644 --- a/form-builder/backend/database.js +++ b/form-builder/backend/database.js @@ -23,9 +23,29 @@ let forms = [ } ]; +let submissions = []; + +function addSubmission(formId, data) { + submissions.push({ formId, data, submittedAt: new Date().toISOString() }); +} + +function getSubmissions(formId) { + return submissions.filter(s => String(s.formId) === String(formId)); +} + +function getSubmissionCount(formId) { + return getSubmissions(formId).length; +} + function getForms() { - // Return only form metadata (not full config) - return forms.map(({ id, name, description, createdAt }) => ({ id, name, description, createdAt })); + // Return only form metadata (not full config), plus filledCount + return forms.map(({ id, name, description, createdAt }) => ({ + id, + name, + description, + createdAt, + filledCount: getSubmissionCount(id) + })); } function getFormById(id) { @@ -59,5 +79,8 @@ module.exports = { getFormById, addForm, updateFormById, - deleteFormById + deleteFormById, + addSubmission, + getSubmissions, + getSubmissionCount }; diff --git a/form-builder/backend/routes/formRoutes.js b/form-builder/backend/routes/formRoutes.js index f4733ae..d64d492 100644 --- a/form-builder/backend/routes/formRoutes.js +++ b/form-builder/backend/routes/formRoutes.js @@ -1,6 +1,6 @@ const express = require('express'); const router = express.Router(); -const { getForms, getFormById, addForm, updateFormById } = require('../database'); +const { getForms, getFormById, addForm, updateFormById, deleteFormById, addSubmission, getSubmissions } = require('../database'); const Form = require('../models/form'); // Get all forms (metadata only) @@ -40,4 +40,20 @@ router.delete('/forms/:id', (req, res) => { res.json({ success: true }); }); +// Submit a filled form +router.post('/forms/:id/submit', (req, res) => { + const form = getFormById(req.params.id); + if (!form) return res.status(404).json({ error: 'Form not found' }); + addSubmission(req.params.id, req.body); + res.status(201).json({ success: true }); +}); + +// Get all submissions for a form +router.get('/forms/:id/submissions', (req, res) => { + const form = getFormById(req.params.id); + if (!form) return res.status(404).json({ error: 'Form not found' }); + const submissions = getSubmissions(req.params.id); + res.json(submissions); +}); + module.exports = router; diff --git a/form-builder/src/App.jsx b/form-builder/src/App.jsx index ef54e45..f2f1fd3 100644 --- a/form-builder/src/App.jsx +++ b/form-builder/src/App.jsx @@ -6,6 +6,7 @@ const App = () => { } /> + } /> } /> } /> } /> diff --git a/form-builder/src/FormBuilder.jsx b/form-builder/src/FormBuilder.jsx index 46c0bb7..79fc0e6 100644 --- a/form-builder/src/FormBuilder.jsx +++ b/form-builder/src/FormBuilder.jsx @@ -5,7 +5,7 @@ import AddForm from './components/AddForm'; import FormBuilderView from './components/FormBuilderView'; import { Share, Edit3 } from 'lucide-react'; import { Button } from './ui'; -import { getForms, getFormById, createForm, updateForm, deleteForm } from './api'; +import { getForms, getFormById, createForm, updateForm, deleteForm, submitForm, getFormSubmissions } from './api'; const FormBuilder = () => { const { id } = useParams(); @@ -19,6 +19,10 @@ const FormBuilder = () => { }); const [editingFormId, setEditingFormId] = useState(null); const [viewingForm, setViewingForm] = useState(null); + const [userFormData, setUserFormData] = useState({}); + const [submitSuccess, setSubmitSuccess] = useState(false); + const [submissions, setSubmissions] = useState([]); + const [userFormErrors, setUserFormErrors] = useState({}); const fieldTypes = [ { type: 'text', label: 'Text Input', icon: '📝' }, @@ -85,6 +89,13 @@ const FormBuilder = () => { // eslint-disable-next-line }, [location.pathname, id]); + // Fetch submissions for view route + useEffect(() => { + if (id && location.pathname.endsWith('/view')) { + getFormSubmissions(id).then(setSubmissions).catch(() => setSubmissions([])); + } + }, [id, location.pathname]); + // Handlers const handleCreateForm = () => navigate('/add'); const handleViewForm = (id) => navigate(`/form/${id}/view`); @@ -92,16 +103,22 @@ const FormBuilder = () => { const handleNextToBuilder = async () => { if (currentForm.template && currentForm.template !== 'blank') { - const templateMeta = forms.find(f => f.name.toLowerCase().includes(currentForm.template)); - if (templateMeta) { - try { - const templateForm = await getFormById(templateMeta.id); - setCurrentForm(prev => ({ ...prev, fields: [...templateForm.fields] })); - } catch { - alert('Failed to load template form'); - console.error('Failed to load template form:', templateMeta.id); - return; + try { + const templateMeta = forms.find(f => f.name.toLowerCase().includes(currentForm.template)); + if (templateMeta) { + try { + const templateForm = await getFormById(templateMeta.id); + setCurrentForm(prev => ({ ...prev, fields: [...templateForm.fields] })); + } catch { + alert('Failed to load template form'); + console.error('Failed to load template form:', templateMeta.id); + return; + } } + } catch (error) { + console.error('Failed to load template:', error); + alert('Failed to load template'); + return; } } navigate('/form/new/edit'); @@ -174,7 +191,6 @@ const FormBuilder = () => { }; const renderFieldPreview = (field) => { - validateForm(); const baseProps = { placeholder: field.placeholder, className: 'w-full' }; switch (field.type) { case 'text': @@ -263,9 +279,35 @@ const FormBuilder = () => { return errors; }; + // Handler for user form submit + const handleUserFormSubmit = async (e) => { + e.preventDefault(); + // Validate required fields + const errors = {}; + if (viewingForm && viewingForm.fields) { + viewingForm.fields.forEach(field => { + if (field.required && (!userFormData[field.id] || userFormData[field.id].toString().trim() === '')) { + errors[field.id] = 'This field is required'; + } + }); + } + setUserFormErrors(errors); + if (Object.keys(errors).length > 0) return; + try { + await submitForm(id, userFormData); + setSubmitSuccess(true); + setUserFormData({}); + setUserFormErrors({}); + } catch { + alert('Failed to submit form'); + } + }; + const handleEditForm = (id) => { + navigate(`/form/${id}/edit`); + }; // Render logic based on route if (location.pathname === '/' || location.pathname === '/dashboard') { - return ; + return ; } if (location.pathname === '/add') { return navigate('/')} handleNextToBuilder={handleNextToBuilder} />; @@ -323,12 +365,40 @@ const FormBuilder = () => {
No fields in this form.
)} + {/* Show filled submissions */} +
+

Filled Submissions ({submissions.length})

+ {submissions.length === 0 ? ( +
No submissions yet.
+ ) : ( +
+ {submissions.map((sub, idx) => ( +
+
Submitted: {new Date(sub.submittedAt).toLocaleString()}
+
    + {Object.entries(sub.data).map(([fid, val]) => ( +
  • {viewingForm.fields.find(f => String(f.id) === String(fid))?.label || fid}: {val}
  • + ))} +
+
+ ))} +
+ )} +
); } if (id && location.pathname.endsWith('/public/preview') && viewingForm) { + if (submitSuccess) { + return ( +
+

Thank you!

+

Your form has been submitted successfully.

+
+ ); + } return (
@@ -337,25 +407,109 @@ const FormBuilder = () => {

{viewingForm.name}

{viewingForm.description}

-
- {viewingForm.fields && viewingForm.fields.length > 0 ? ( - viewingForm.fields.map((field, idx) => ( -
- - {/* Render field preview (read-only) */} - {renderFieldPreview(field)} - {field.helperText && ( -

{field.helperText}

- )} -
- )) - ) : ( -
No fields in this form.
- )} -
+
+ {viewingForm.fields.map(field => ( +
+ + {field.type === 'text' && ( + setUserFormData(prev => ({ ...prev, [field.id]: e.target.value }))} + placeholder={field.placeholder} + required={field.required} + /> + )} + {field.type === 'textarea' && ( +