Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added eduaid_web/backend/form-handler.gs
Binary file not shown.
124 changes: 103 additions & 21 deletions eduaid_web/src/App.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,107 @@
import "./App.css";
import { Routes, Route, HashRouter } from "react-router-dom";
import Home from "./pages/Home";
import Question_Type from "./pages/Question_Type";
import Text_Input from "./pages/Text_Input";
import Output from "./pages/Output";
import Previous from "./pages/Previous";
import NotFound from "./pages/PageNotFound";

function App() {
import React, { useEffect, useState } from "react";

function DynamicForm() {
const [questions, setQuestions] = useState([]);
const [responses, setResponses] = useState({});

// Fetch form questions from Google Apps Script
useEffect(() => {
fetch(
"https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec"
)
Comment on lines +9 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Move the Google Apps Script URL to environment variables.

The script URL is hardcoded, which exposes the endpoint and makes environment-specific configuration difficult.

  useEffect(() => {
    fetch(
-      "https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec"
+      process.env.REACT_APP_GOOGLE_SCRIPT_URL
    )

Add to .env:

REACT_APP_GOOGLE_SCRIPT_URL=https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fetch(
"https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec"
)
fetch(
process.env.REACT_APP_GOOGLE_SCRIPT_URL
)
🤖 Prompt for AI Agents
In eduaid_web/src/App.js around lines 9-11 the Google Apps Script URL is
hardcoded; move this value into an environment variable by adding
REACT_APP_GOOGLE_SCRIPT_URL=<the URL> to .env, then update the fetch call to
read from process.env.REACT_APP_GOOGLE_SCRIPT_URL (and add a clear runtime error
or fallback if the env var is missing) so the endpoint is configurable per
environment and no secrets/URLs are hardcoded in source.

.then((res) => res.json())
.then((data) => setQuestions(data))
.catch((err) => console.error("Error fetching form:", err));
}, []);

const handleChange = (id, value) => {
setResponses((prev) => ({ ...prev, [id]: value }));
};

const handleSubmit = (e) => {
e.preventDefault();
console.log("User Responses:", responses);
alert("Form submitted! Check console for responses.");
};

return (
<HashRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/question-type" element={<Question_Type />} />
<Route path="/input" element={<Text_Input />} />
<Route path="/output" element={<Output />} />
<Route path="/history" element={<Previous />} />
<Route path="*" element={<NotFound />} />
</Routes>
</HashRouter>
<div style={{ padding: "20px" }}>
<h2>Dynamic Google Form</h2>
<form onSubmit={handleSubmit}>
{questions.map((q) => (
<div key={q.id} style={{ marginBottom: "20px" }}>
<label>
<strong>{q.title}</strong>
</label>
<br />

{q.type === "TEXT" && (
<input
type="text"
onChange={(e) => handleChange(q.id, e.target.value)}
/>
)}

{q.type === "PARAGRAPH_TEXT" && (
<textarea
rows="4"
cols="40"
onChange={(e) => handleChange(q.id, e.target.value)}
/>
)}

{q.type === "CHECKBOX" &&
q.choices?.map((choice, i) => (
<label key={i} style={{ display: "block" }}>
<input
type="checkbox"
value={choice}
onChange={(e) => {
const prev = responses[q.id] || [];
if (e.target.checked) {
handleChange(q.id, [...prev, choice]);
} else {
handleChange(
q.id,
prev.filter((c) => c !== choice)
);
}
}}
/>
{choice}
</label>
))}

{q.type === "LIST" && (
<select onChange={(e) => handleChange(q.id, e.target.value)}>
<option value="">Select</option>
{q.choices?.map((choice, i) => (
<option key={i} value={choice}>
{choice}
</option>
))}
</select>
)}

{q.type === "MULTIPLE_CHOICE" &&
q.choices?.map((choice, i) => (
<label key={i} style={{ display: "block" }}>
<input
type="radio"
name={q.id}
value={choice}
onChange={(e) => handleChange(q.id, e.target.value)}
/>
{choice}
</label>
))}
</div>
))}

<button type="submit">Submit</button>
</form>
</div>
);
}

export default App;
export default DynamicForm;
113 changes: 113 additions & 0 deletions eduaid_web/src/DynamicForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React, { useEffect, useState } from "react";

function DynamicForm() {
const [questions, setQuestions] = useState([]);
const [answers, setAnswers] = useState({});

// 👉 Replace this with your deployed Google Apps Script URL
const GOOGLE_SCRIPT_URL =
"https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec";
Comment on lines +7 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Move the Google Apps Script URL to environment variables.

Hardcoding the script URL exposes the endpoint publicly and makes it difficult to maintain across environments (dev, staging, prod).

Move to an environment variable:

-  // 👉 Replace this with your deployed Google Apps Script URL
-  const GOOGLE_SCRIPT_URL =
-    "https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec";
+  const GOOGLE_SCRIPT_URL = process.env.REACT_APP_GOOGLE_SCRIPT_URL;

Then add to .env:

REACT_APP_GOOGLE_SCRIPT_URL=https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 👉 Replace this with your deployed Google Apps Script URL
const GOOGLE_SCRIPT_URL =
"https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec";
const GOOGLE_SCRIPT_URL = process.env.REACT_APP_GOOGLE_SCRIPT_URL;
🤖 Prompt for AI Agents
In eduaid_web/src/DynamicForm.js around lines 7 to 9 the Google Apps Script URL
is hardcoded; replace it with an environment variable reference
(process.env.REACT_APP_GOOGLE_SCRIPT_URL) and remove the literal string, update
.env with REACT_APP_GOOGLE_SCRIPT_URL=<your-script-url>, and add a safe fallback
or throw a clear error if the env var is missing so builds fail fast in
non-configured environments.


// Fetch questions from Google Script
useEffect(() => {
fetch(GOOGLE_SCRIPT_URL)
.then((res) => res.json())
.then((data) => {
console.log("Fetched form data:", data);
setQuestions(data);
})
.catch((err) => console.error("Error fetching form data:", err));
}, []);
Comment on lines +12 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add loading state and improve error handling.

The component doesn't indicate when data is being fetched, and errors are only logged without user feedback.

Apply this diff:

 function DynamicForm() {
   const [questions, setQuestions] = useState([]);
   const [answers, setAnswers] = useState({});
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);

   const GOOGLE_SCRIPT_URL =
     "https://script.google.com/macros/s/AKfycbxRamNfuS1b9yBXapdCs9gB3ScRhpxiRPbjTO0qrzeYel0BJEq4VyTGX3GnZ_-KIsZXkw/exec";

   useEffect(() => {
+    setLoading(true);
     fetch(GOOGLE_SCRIPT_URL)
       .then((res) => res.json())
       .then((data) => {
         console.log("Fetched form data:", data);
         setQuestions(data);
+        setLoading(false);
       })
-      .catch((err) => console.error("Error fetching form data:", err));
+      .catch((err) => {
+        console.error("Error fetching form data:", err);
+        setError("Failed to load form. Please try again later.");
+        setLoading(false);
+      });
   }, []);

Then update the render logic to show loading/error states:

  if (loading) return <div>Loading form...</div>;
  if (error) return <div style={{ color: "red" }}>{error}</div>;
🤖 Prompt for AI Agents
In eduaid_web/src/DynamicForm.js around lines 12 to 20, the component fetch
logic lacks a loading state and user-visible error handling; update the
component to add local state variables (loading and error), set loading=true
before fetch, set loading=false and setQuestions(data) on success, and set
loading=false and setError with a user-friendly message on catch; then update
the render to return a loading placeholder when loading is true and an error
message styled in red when error is set (i.e., if (loading) return <div>Loading
form...</div>; if (error) return <div style={{ color: "red" }}>{error}</div>;).


// Handle input change
const handleChange = (id, value) => {
setAnswers((prev) => ({ ...prev, [id]: value }));
};

// Handle form submission
const handleSubmit = (e) => {
e.preventDefault();
console.log("Submitted answers:", answers);
alert("Form submitted! Check console for answers.");
};
Comment on lines +28 to +32
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Implement actual form submission and validation.

The form currently only logs responses locally without submitting them to the Google Apps Script endpoint or validating required fields.

Consider implementing:

  1. POST request to submit responses to the backend
  2. Validation for required fields
  3. Better user feedback (e.g., success message, loading spinner)

Example:

  const handleSubmit = (e) => {
    e.preventDefault();
+    
+    // Validate required fields
+    const requiredQuestions = questions.filter(q => q.required);
+    const missingAnswers = requiredQuestions.filter(q => !answers[q.id]);
+    if (missingAnswers.length > 0) {
+      alert("Please answer all required questions.");
+      return;
+    }
+    
+    // Submit to backend
+    setLoading(true);
+    fetch(GOOGLE_SCRIPT_URL, {
+      method: 'POST',
+      headers: { 'Content-Type': 'application/json' },
+      body: JSON.stringify(answers)
+    })
+      .then(res => res.json())
+      .then(data => {
+        alert("Form submitted successfully!");
+        console.log("Submitted answers:", answers);
+        setLoading(false);
+      })
+      .catch(err => {
+        alert("Failed to submit form. Please try again.");
+        console.error("Submission error:", err);
+        setLoading(false);
+      });
-    console.log("Submitted answers:", answers);
-    alert("Form submitted! Check console for answers.");
  };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleSubmit = (e) => {
e.preventDefault();
console.log("Submitted answers:", answers);
alert("Form submitted! Check console for answers.");
};
const handleSubmit = (e) => {
e.preventDefault();
// Validate required fields
const requiredQuestions = questions.filter(q => q.required);
const missingAnswers = requiredQuestions.filter(q => !answers[q.id]);
if (missingAnswers.length > 0) {
alert("Please answer all required questions.");
return;
}
// Submit to backend
setLoading(true);
fetch(GOOGLE_SCRIPT_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(answers)
})
.then(res => res.json())
.then(data => {
alert("Form submitted successfully!");
console.log("Submitted answers:", answers);
setLoading(false);
})
.catch(err => {
alert("Failed to submit form. Please try again.");
console.error("Submission error:", err);
setLoading(false);
});
};
🤖 Prompt for AI Agents
In eduaid_web/src/DynamicForm.js around lines 28 to 32, the form submit handler
only logs answers and shows an alert; replace it with real submission and
validation: validate required fields before sending, show inline validation
errors, set a loading state to disable the submit button and display a spinner
while submitting, send a POST (fetch/axios) to the Google Apps Script endpoint
with the answers as JSON and appropriate headers, await the response and handle
non-2xx responses as errors, show a success message on completion and clear or
preserve form per UX decision, and catch/network errors to show a user-friendly
error message and re-enable the form. Ensure to prevent multiple submissions and
include minimal retry/backoff or instructive error text for failed submissions.


return (
<div style={{ padding: "20px" }}>
<h2>Dynamic Google Form</h2>
<form onSubmit={handleSubmit}>
{questions.map((q) => (
<div key={q.id} style={{ marginBottom: "20px" }}>
<label>
<strong>{q.title}</strong>
</label>
<br />

{/* Render inputs based on question type */}
{q.type === "TEXT" && (
<input
type="text"
onChange={(e) => handleChange(q.id, e.target.value)}
/>
)}

{q.type === "PARAGRAPH_TEXT" && (
<textarea
onChange={(e) => handleChange(q.id, e.target.value)}
></textarea>
)}

{q.type === "MULTIPLE_CHOICE" &&
q.choices?.map((choice, i) => (
<div key={i}>
<input
type="radio"
name={q.id}
value={choice}
onChange={(e) => handleChange(q.id, e.target.value)}
/>
{choice}
</div>
))}

{q.type === "CHECKBOX" &&
q.choices?.map((choice, i) => (
<div key={i}>
<input
type="checkbox"
value={choice}
onChange={(e) => {
const selected = answers[q.id] || [];
if (e.target.checked) {
handleChange(q.id, [...selected, choice]);
} else {
handleChange(
q.id,
selected.filter((c) => c !== choice)
);
}
}}
/>
{choice}
</div>
))}

{q.type === "LIST" && (
<select onChange={(e) => handleChange(q.id, e.target.value)}>
<option value="">Select</option>
{q.choices?.map((choice, i) => (
<option key={i} value={choice}>
{choice}
</option>
))}
</select>
)}
</div>
))}

<button type="submit">Submit</button>
</form>
</div>
);
}

export default DynamicForm;