feat: implement form drafts, temporary public links, and automated em… - #8
Conversation
…ail notifications
✅ Deploy Preview for leddger-ai ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a template-builder workflow (Student/Employee/Team) with saved drafts and public, expiring share links, backed by a new Node/Express + MongoDB server that persists drafts/submissions and sends email notifications. It also refactors the app shell UI into a 2-tier sidebar “floating window” layout and removes previously generated placeholder utility files/scripts.
Changes:
- Add template builder pages with live preview, plus a public form submission view.
- Add a new
server/Express app for departments, draft creation, public form retrieval/submission, and email notifications. - Refactor navigation/app shell to router-driven dashboard URLs + new 2-tier sidebar layout, and update branding assets (favicon/logo).
Reviewed changes
Copilot reviewed 36 out of 41 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| submissions/ai-leddger_chitkul-lakshya.md | Removes a project submission markdown file from the repo. |
| src/utils/validators.js | Removes generated placeholder comment-only content. |
| src/utils/themeEngine.js | Removes generated placeholder utility code. |
| src/utils/notificationService.js | Removes generated placeholder utility code. |
| src/utils/graphProcessor.js | Removes generated placeholder utility code. |
| src/utils/formatters.js | Removes generated placeholder comment-only content. |
| src/utils/exportUtils.js | Removes generated placeholder utility code. |
| src/utils/collaborationEngine.js | Removes generated placeholder utility code. |
| src/pages/TemplateBuilder.css | Adds shared styling for template builders + preview UI. |
| src/pages/TeamTemplateBuilder.jsx | Adds team template builder with department options + draft link generation. |
| src/pages/StudentTemplateBuilder.jsx | Adds student template builder with bracket-syntax email template preview. |
| src/pages/PublicFormView.jsx | Adds public form view for loading a draft and submitting responses. |
| src/pages/EmployeeTemplateBuilder.jsx | Adds employee template builder with bracket-syntax email template preview. |
| src/LandingPage.jsx | Updates landing navbar branding to include logo image. |
| src/index.css | Changes global body layout/background styling (canvas centering behavior). |
| src/components/ProtectedRoute.jsx | Adds route guard that waits for auth readiness before redirecting. |
| src/App.jsx | Refactors routing + dashboard shell/navigation and adds template builder routes. |
| src/App.css | Adds new 2-tier sidebar + “floating window” layout styles. |
| server/utils/emailService.js | Adds Gmail OAuth2 nodemailer email sender for form submissions. |
| server/package.json | Adds backend Node server package manifest and dependencies. |
| server/models/User.js | Adds Mongo model for storing per-user department options. |
| server/models/FormSubmission.js | Adds Mongo model for storing public form submissions. |
| server/models/FormDraft.js | Adds Mongo model for storing expiring form drafts. |
| server/middleware/auth.js | Adds Firebase Admin ID-token verification middleware (with dev behavior). |
| server/index.js | Adds Express API for departments, draft creation, form retrieval/submission, and email trigger. |
| package.json | Switches dev backend script to run the new Node server; bumps react-router-dom. |
| package-lock.json | Updates lockfile for react-router-dom version bump. |
| index.html | Switches favicon/app icons to logo.webp. |
| generate_commits.py | Removes mock history generation script. |
| generate_author_commits.py | Removes mock author/commit generation script. |
| docs/ui-layout-refactor.md | Documents the new “box-in-a-box” floating layout refactor. |
| docs/sidebar-architecture.md | Documents the new 2-tier sidebar architecture. |
| docs/CHANGELOG.md | Adds comprehensive changelog documenting project history and new features. |
| docs/authentication-flow.md | Documents auth persistence and demo-mode behavior. |
| .gitignore | Adds ignore entry for a private key file. |
Suppressed comments (3)
src/pages/PublicFormView.jsx:57
- This submit endpoint is also hard-coded to
http://localhost:5000. Use an environment-based base URL so public links work outside local dev.
const response = await fetch(`http://localhost:5000/api/forms/${draftId}/submit`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ submittedData: formData })
});
src/pages/TeamTemplateBuilder.jsx:154
- The generated public link is hard-coded to
http://localhost:5173, so it will be wrong in production/preview environments. Usewindow.location.origin(or a configured public base URL).
setDraftLink(`http://localhost:5173/form/${encodeURIComponent(formTitle)}/${data.draftId}`);
server/middleware/auth.js:36
- When Firebase Admin isn’t initialized, the middleware silently bypasses authentication and treats any Bearer token as valid. This is extremely risky if the required env vars are missing/misconfigured in a deployed environment.
if (!adminInitialized) {
// Development bypass if no service account key is provided yet
req.user = { uid: "DEV_MOCK_UID_" + idToken.substring(0, 5) };
return next();
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import ExportView from './ExportView.jsx'; | ||
| import EmailAutomationView from './EmailAutomationView.jsx'; | ||
| import AnalysisView from './AnalysisView.jsx'; | ||
| import StudentTemplateBuilder from './pages/StudentTemplateBuilder.jsx'; | ||
| import EmployeeTemplateBuilder from './pages/EmployeeTemplateBuilder.jsx'; | ||
| import TeamTemplateBuilder from './pages/TeamTemplateBuilder.jsx'; | ||
| import ProtectedRoute from './components/ProtectedRoute.jsx'; |
| -webkit-font-smoothing: antialiased; | ||
| -moz-osx-font-smoothing: grayscale; | ||
| overflow-x: hidden; | ||
| overflow: hidden; | ||
| height: 100vh; | ||
| margin: 0; |
| .layout-wrapper { | ||
| display: flex; | ||
| gap: 12px; | ||
| width: calc(100vw - 32px); | ||
| height: calc(100vh - 32px); | ||
| } |
| useEffect(() => { | ||
| const fetchForm = async () => { | ||
| try { | ||
| const response = await fetch(`http://localhost:5000/api/forms/${draftId}`); |
| const initialData = {}; | ||
| if (data.config.toggles.teamTitle) initialData.teamTitle = data.config.titlePrefix || ''; | ||
| if (data.config.toggles.department) initialData.department = ''; |
| crossFunctional | ||
| }; | ||
|
|
||
| const token = await auth.currentUser.getIdToken(); |
| const fs = require('fs'); | ||
| const path = require('path'); |
| const app = express(); | ||
| app.use(cors()); | ||
| app.use(express.json()); |
| const sendFormSubmissionEmail = async (formTitle, submittedData, recruiterEmail) => { | ||
| try { | ||
| const transporter = await createTransporter(); | ||
|
|
||
| const dataString = Object.entries(submittedData) | ||
| .map(([key, value]) => `<strong>${key}:</strong> ${value}`) | ||
| .join('<br>'); | ||
|
|
||
| const mailOptions = { | ||
| from: process.env.GOOGLE_EMAIL, | ||
| to: recruiterEmail || process.env.GOOGLE_EMAIL, // Send to recruiter, fallback to self | ||
| subject: `New Form Submission: ${formTitle}`, | ||
| html: ` | ||
| <h2>New Submission for ${formTitle}</h2> | ||
| <p>A user has just completed your form draft.</p> | ||
| <div style="background-color: #f9f9f9; padding: 15px; border-radius: 5px;"> | ||
| ${dataString} | ||
| </div> | ||
| ` | ||
| }; |
| const response = await fetch('http://localhost:5000/api/drafts', { | ||
| method: 'POST', |
…ail notifications