Skip to content

feat: add LinkedIn sharing with pre-filled caption copy on card export (closes #521)#526

Open
singhanurag0317-bit wants to merge 1 commit into
Eswaramuthu:mainfrom
singhanurag0317-bit:fix/linkedin-share-521
Open

feat: add LinkedIn sharing with pre-filled caption copy on card export (closes #521)#526
singhanurag0317-bit wants to merge 1 commit into
Eswaramuthu:mainfrom
singhanurag0317-bit:fix/linkedin-share-521

Conversation

@singhanurag0317-bit
Copy link
Copy Markdown

Implement dynamic achievement card export combined with a direct LinkedIn sharing option.

  • Adds a premium "Share on LinkedIn" button styled with standard LinkedIn branding colors and SVG logo on the card export interface.
  • Extracts the achievement's details (Event, Organizer, Position, Verification URL) from the DOM.
  • Copies a details-rich formatted caption to the user's clipboard:
    I am thrilled to share my achievement! 🎖️ I secured {position} in "{event_name}" organized by "{organizer}". Verify it here: {verification_url}
  • Displays toast/status feedback on success.
  • Opens LinkedIn's sharing dialogue in a new tab.

Closes #521

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 7, 2026

Someone is attempting to deploy a commit to the 007's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 7, 2026

Thanks for creating a PR for your Issue! ☺️

We'll review it as soon as possible.
In the meantime, please double-check the file changes and ensure that all commits are accurate.

If there are any unresolved review comments, feel free to resolve them. 🙌🏼

Comment on lines +303 to +336
await navigator.clipboard.writeText(captionText);
copied = true;
} catch (clipErr) {
console.warn('Clipboard write failed:', clipErr);
}
}

// Provide UI feedback
if (this.statusDiv) {
this.statusDiv.style.display = 'flex';
if (copied) {
this.showSuccessMessage('Caption copied! Opening LinkedIn...');
} else {
// Graceful fallback display
this.showSuccessMessage('Opening LinkedIn...');
}

// Reset status spinner/text after a delay
setTimeout(() => {
this.statusDiv.style.display = 'none';
// Reset styling to original states
this.statusDiv.style.background = '';
this.statusDiv.style.color = '';
const spinner = this.statusDiv.querySelector('.status-spinner');
if (spinner) {
spinner.textContent = '⏳';
spinner.style.animation = '';
}
}, 3000);
}

// Open LinkedIn share dialog in a new tab
const shareUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(verificationUrl)}`;
window.open(shareUrl, '_blank');
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.

MAJOR BUG window.open blocked by popup blocker after clipboard await

The await navigator.clipboard.writeText(...) at line 303 suspends the async function and releases the browser's user-gesture context; when window.open runs at line 336, browsers (Chrome, Firefox, Safari) no longer consider it user-initiated and silently block the popup.

Suggested change
await navigator.clipboard.writeText(captionText);
copied = true;
} catch (clipErr) {
console.warn('Clipboard write failed:', clipErr);
}
}
// Provide UI feedback
if (this.statusDiv) {
this.statusDiv.style.display = 'flex';
if (copied) {
this.showSuccessMessage('Caption copied! Opening LinkedIn...');
} else {
// Graceful fallback display
this.showSuccessMessage('Opening LinkedIn...');
}
// Reset status spinner/text after a delay
setTimeout(() => {
this.statusDiv.style.display = 'none';
// Reset styling to original states
this.statusDiv.style.background = '';
this.statusDiv.style.color = '';
const spinner = this.statusDiv.querySelector('.status-spinner');
if (spinner) {
spinner.textContent = '⏳';
spinner.style.animation = '';
}
}, 3000);
}
// Open LinkedIn share dialog in a new tab
const shareUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(verificationUrl)}`;
window.open(shareUrl, '_blank');
// Copy to clipboard first (sync gesture preserved), then open tab
const shareUrl = `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(verificationUrl)}`;
const tab = window.open(shareUrl, '_blank', 'noopener,noreferrer');
// Try to copy to clipboard
let copied = false;
if (navigator.clipboard && navigator.clipboard.writeText) {
try {
await navigator.clipboard.writeText(captionText);
copied = true;
} catch (clipErr) {
console.warn('Clipboard write failed:', clipErr);
}
}
Prompt to fix with AI

Copy this prompt into your AI coding assistant to fix this issue.

In `static/js/achievement-export.js`, inside the `shareLinkedIn()` method (lines 281-342), the `window.open(shareUrl, '_blank')` call at line 336 is placed after `await navigator.clipboard.writeText(captionText)` at line 303. This breaks popup blocking rules: browsers only permit window.open in a synchronous user-gesture handler, and the await suspends the function, releasing that context. Fix by moving the `window.open` call to BEFORE the first `await` (i.e., before line 303), so it executes synchronously within the click handler. Also add `'noopener,noreferrer'` as the third argument to window.open.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown
Contributor


Confidence Score: 3/5 - Review Recommended

Not safe to merge without fixes — the LinkedIn sharing feature in achievement-export.js contains a functional bug where window.open() is called after an await navigator.clipboard.writeText(), which suspends the async function and breaks the browser's user-gesture activation chain, causing popup blockers to suppress the LinkedIn share window in most browsers. This PR achieves a useful UX improvement by pre-filling caption copy on card export for LinkedIn sharing, and the clipboard logic itself is correct, but the ordering of async clipboard writes before synchronous window opens is a well-known cross-browser pitfall that will silently fail for most users. The fix requires either opening the window before the clipboard await or using a synchronous fallback pattern to preserve the user gesture trust.

Key Findings:

  • In achievement-export.js around line 303, await navigator.clipboard.writeText(...) is called before window.open(linkedInUrl), which releases the user-gesture activation context required for popup permission — most browsers (Chrome, Firefox, Safari) will block the window.open call silently after the async suspension, making the LinkedIn share link non-functional for the majority of users.
  • The clipboard write itself is correctly implemented and provides a good UX pattern (pre-filling the caption), but sequencing it before the window open inverts the correct order — window.open must be called synchronously within the user gesture handler, with the clipboard write optionally following or being handled via a fallback.
  • No pre-existing unresolved issues were identified in other changed files, and the overall PR scope appears focused and well-contained to the export functionality.
Files requiring special attention
  • static/js/achievement-export.js

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.

Feature: Implement Dynamic Card Export and Direct LinkedIn Sharing

1 participant