Skip to content

Added Share feature with modal and backend route integration#104

Open
Vibhasha-5 wants to merge 1 commit into
DhanushNehru:mainfrom
Vibhasha-5:feature/share-modal
Open

Added Share feature with modal and backend route integration#104
Vibhasha-5 wants to merge 1 commit into
DhanushNehru:mainfrom
Vibhasha-5:feature/share-modal

Conversation

@Vibhasha-5

@Vibhasha-5 Vibhasha-5 commented Oct 31, 2025

Copy link
Copy Markdown

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:

  • Added ShareModal.tsx component for displaying and copying shareable links.
  • Updated NoteView.tsx to include a “Share” button that toggles the modal.
  • Integrated the modal using React state for smooth UX.
  • Styled components using Tailwind for consistent UI.

Backend:

  • Added /share/:id route to handle shareable note retrieval (read-only access).
  • Implemented logic for fetching note data based on ID securely.
  • Enabled cross-origin support for frontend access if needed.

Testing Steps:

  1. Run backend:
    cd backend
    npm start

  2. Run frontend
    npm run dev

  3. Open the app → select a note → click Share → verify modal and share link.

Fixes Issues:

Issue No #94

@vercel

vercel Bot commented Oct 31, 2025

Copy link
Copy Markdown

@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.

@vercel

vercel Bot commented Oct 31, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
scratchpad-scribe Ready Ready Preview Comment Oct 31, 2025 2:42pm

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Comment thread src/pages/publicShare.tsx
Comment on lines +5 to +8
export default function PublicShare() {
const { token } = useParams<{ token: string }>();
const [loading, setLoading] = useState(true);
const [note, setNote] = useState<any>(null);

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

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.

Suggested change
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);

Copilot uses AI. Check for mistakes.
'1h': 3600,
'1d': 86400,
};
const body: any = { noteId };

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

Replace any type with a proper type definition. Define an interface like { noteId: string; expiresInSeconds?: number } for better type safety.

Copilot uses AI. Check for mistakes.
if (res.ok) {
setLink(data.url);
} else {
alert(data.message || 'Failed to create share link');

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

Using alert() for error handling is not ideal for modern web applications. Consider using a toast notification system for better user experience.

Copilot uses AI. Check for mistakes.
function copyLink() {
if (!link) return;
navigator.clipboard.writeText(link).then(()=> {
alert('Copied!');

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

Using alert() for success feedback is not ideal. Consider using a toast notification system for better user experience.

Copilot uses AI. Check for mistakes.
if (!link) return;
navigator.clipboard.writeText(link).then(()=> {
alert('Copied!');
}).catch(()=> alert('Failed to copy'));

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

Using alert() for error handling is not ideal. Consider using a toast notification system for better user experience.

Copilot uses AI. Check for mistakes.
Comment thread backend/server.js
Comment on lines +11 to +12
const shareRoutes = require("./routes/share");
app.use("/api/share", shareRoutes);

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

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.

Suggested change
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);

Copilot uses AI. Check for mistakes.
const Share = require('../models/Share');
const Note = require('../models/Note');

function makeToken(len = 24) {

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

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.

Suggested change
function makeToken(len = 24) {
function makeToken(len) {

Copilot uses AI. Check for mistakes.
});
await shareDoc.save();

const base = process.env.SHARE_BASE_URL || process.env.BASE_URL || 'http://localhost:3000';

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

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.

Suggested change
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");
}
}

Copilot uses AI. Check for mistakes.
// --- START: THIRD-PARTY EMOJI LIBRARY IMPORTS ---
import Picker from '@emoji-mart/react';
import data from '@emoji-mart/data';
import Picker from "@emoji-mart/react";

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

Unused import Picker.

Suggested change
import Picker from "@emoji-mart/react";

Copilot uses AI. Check for mistakes.
import Picker from '@emoji-mart/react';
import data from '@emoji-mart/data';
import Picker from "@emoji-mart/react";
import data from "@emoji-mart/data";

Copilot AI Oct 31, 2025

Copy link

Choose a reason for hiding this comment

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

Unused import data.

Suggested change
import data from "@emoji-mart/data";

Copilot uses AI. Check for mistakes.
@DhanushNehru

Copy link
Copy Markdown
Owner

Linting failed @Vibhasha-5 please check

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants