Added Share feature with modal and backend route integration#104
Added Share feature with modal and backend route integration#104Vibhasha-5 wants to merge 1 commit into
Conversation
|
@Vibhasha-5 is attempting to deploy a commit to the Dhanush Nehru's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull Request Overview
This PR implements a public read-only sharing feature for notes, allowing users to generate shareable links with optional expiration times.
- Adds a new public share page (
/s/:token) to display shared notes in read-only mode - Introduces a ShareModal component for creating and managing share links with configurable expiration (never, 1 hour, 1 day)
- Implements backend infrastructure including database models, controllers, and routes to support share link generation, validation, and revocation
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| src/pages/publicShare.tsx | New public page component that fetches and displays shared notes by token |
| src/components/ShareModal.tsx | New modal component for creating shareable links with expiration options |
| src/components/NoteEditor.tsx | Integrates ShareModal by adding a Share button and managing modal visibility state |
| backend/server.js | New Express server setup with MongoDB connection and share routes registration |
| backend/routes/share.js | Defines routes for creating and revoking share links |
| backend/models/Share.js | Mongoose model for storing share link data with expiration logic |
| backend/controllers/shareController.js | Controller logic for creating, fetching, and revoking share links |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export default function PublicShare() { | ||
| const { token } = useParams<{ token: string }>(); | ||
| const [loading, setLoading] = useState(true); | ||
| const [note, setNote] = useState<any>(null); |
There was a problem hiding this comment.
Replace any type with a proper type definition. Consider defining an interface like { title: string; content: string; createdAt?: string; updatedAt?: string } or importing a shared Note type.
| export default function PublicShare() { | |
| const { token } = useParams<{ token: string }>(); | |
| const [loading, setLoading] = useState(true); | |
| const [note, setNote] = useState<any>(null); | |
| interface Note { | |
| title: string; | |
| content: string; | |
| createdAt?: string; | |
| updatedAt?: string; | |
| } | |
| export default function PublicShare() { | |
| const { token } = useParams<{ token: string }>(); | |
| const [loading, setLoading] = useState(true); | |
| const [note, setNote] = useState<Note | null>(null); |
| '1h': 3600, | ||
| '1d': 86400, | ||
| }; | ||
| const body: any = { noteId }; |
There was a problem hiding this comment.
Replace any type with a proper type definition. Define an interface like { noteId: string; expiresInSeconds?: number } for better type safety.
| if (res.ok) { | ||
| setLink(data.url); | ||
| } else { | ||
| alert(data.message || 'Failed to create share link'); |
There was a problem hiding this comment.
Using alert() for error handling is not ideal for modern web applications. Consider using a toast notification system for better user experience.
| function copyLink() { | ||
| if (!link) return; | ||
| navigator.clipboard.writeText(link).then(()=> { | ||
| alert('Copied!'); |
There was a problem hiding this comment.
Using alert() for success feedback is not ideal. Consider using a toast notification system for better user experience.
| if (!link) return; | ||
| navigator.clipboard.writeText(link).then(()=> { | ||
| alert('Copied!'); | ||
| }).catch(()=> alert('Failed to copy')); |
There was a problem hiding this comment.
Using alert() for error handling is not ideal. Consider using a toast notification system for better user experience.
| const shareRoutes = require("./routes/share"); | ||
| app.use("/api/share", shareRoutes); |
There was a problem hiding this comment.
The route /api/share is registered in the backend, but the getSharedNote controller function exported in shareController.js is never registered to any route. The publicShare.tsx component fetches from /s/:token, which has no corresponding backend route defined.
| const shareRoutes = require("./routes/share"); | |
| app.use("/api/share", shareRoutes); | |
| const shareRoutes = require("./routes/share"); | |
| const { getSharedNote } = require("./controllers/shareController"); | |
| app.use("/api/share", shareRoutes); | |
| app.get("/s/:token", getSharedNote); |
| const Share = require('../models/Share'); | ||
| const Note = require('../models/Note'); | ||
|
|
||
| function makeToken(len = 24) { |
There was a problem hiding this comment.
The makeToken function accepts a len parameter for byte length but is always called with 18 on line 19. The default parameter value of 24 is never used. Consider either removing the default value or documenting why different lengths might be needed.
| function makeToken(len = 24) { | |
| function makeToken(len) { |
| }); | ||
| await shareDoc.save(); | ||
|
|
||
| const base = process.env.SHARE_BASE_URL || process.env.BASE_URL || 'http://localhost:3000'; |
There was a problem hiding this comment.
The fallback URL 'http://localhost:3000' could be exposed in production if environment variables are not properly configured. Consider throwing an error or logging a warning in production environments when BASE_URL is not set.
| const base = process.env.SHARE_BASE_URL || process.env.BASE_URL || 'http://localhost:3000'; | |
| let base = process.env.SHARE_BASE_URL || process.env.BASE_URL; | |
| if (!base) { | |
| if (process.env.NODE_ENV === 'production') { | |
| console.error("BASE_URL or SHARE_BASE_URL must be set in production environment."); | |
| return res.status(500).json({ message: "Server misconfiguration: BASE_URL not set" }); | |
| } else { | |
| base = 'http://localhost:3000'; | |
| console.warn("Warning: BASE_URL not set, falling back to http://localhost:3000"); | |
| } | |
| } |
| // --- START: THIRD-PARTY EMOJI LIBRARY IMPORTS --- | ||
| import Picker from '@emoji-mart/react'; | ||
| import data from '@emoji-mart/data'; | ||
| import Picker from "@emoji-mart/react"; |
There was a problem hiding this comment.
Unused import Picker.
| import Picker from "@emoji-mart/react"; |
| import Picker from '@emoji-mart/react'; | ||
| import data from '@emoji-mart/data'; | ||
| import Picker from "@emoji-mart/react"; | ||
| import data from "@emoji-mart/data"; |
There was a problem hiding this comment.
Unused import data.
| import data from "@emoji-mart/data"; |
|
Linting failed @Vibhasha-5 please check |
This pull request introduces a new “Share” functionality that allows users to share their notes via a generated link. The implementation includes both frontend and backend changes to support modal interaction and secure note sharing.
Changes Made:
Frontend:
Backend:
Testing Steps:
Run backend:
cd backend
npm start
Run frontend
npm run dev
Open the app → select a note → click Share → verify modal and share link.
Fixes Issues:
Issue No #94