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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ Resonate is a social voice platform, similar to Clubhouse and Twitter Spaces, bu
5. Pair chatting to enable users to find random partners to talk to in the app.
6. Friend People/Profiles enabling your self to talk on voice calls/realtime messaging with them

## 📺 Project Demo

Watch the Resonate Website in action with SocialShareButton:
[**Project Demo Video**](https://drive.google.com/file/d/12gu3D8wuIiDhwZvS12MaiEfg6CFZGTMv/view?usp=sharing)

Comment on lines +18 to +22
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

PR closure target appears mismatched with linked issue objective.

This change documents SocialShareButton, but the linked Issue #19 objective is mobile navigation (hamburger/menu accessibility). Please avoid auto-closing that issue from this PR unless the nav requirements are implemented here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 18 - 22, The README's Project Demo documents
SocialShareButton but references Issue `#19` (mobile navigation) — remove any
auto-closing keywords or issue-closing syntax and clarify linkage: in the
"Project Demo" / SocialShareButton note, replace any phrasing like "fixes `#19`"
or "closes `#19`" with "related to Issue `#19`" and add a short line that mobile
navigation (hamburger/menu accessibility) is not implemented here; also update
the PR description to avoid auto-closing Issue `#19` and explicitly state that the
mobile nav requirements remain outstanding. Ensure references point to
SocialShareButton and Issue `#19` (mobile navigation / hamburger/menu
accessibility) so reviewers can locate the discrepancy.

## :link: Repository Links

1. [Resonate Flutter App](https://github.com/AOSSIE-Org/Resonate)
Expand Down
14 changes: 14 additions & 0 deletions app/components/Layout/Footer/Footer.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,17 @@
font-size: 1.2rem;
}
}
/* 🔥 FIX: Make button visible */
.social-share-btn {
background: linear-gradient(135deg, #2563eb, #7c3aed) !important;
border: none !important;
color: #fff !important;
padding: 10px 16px;
border-radius: 8px;
cursor: pointer;
}

.social-share-btn:hover {
background: linear-gradient(135deg, #1d4ed8, #6d28d9) !important;
box-shadow: 0 4px 15px rgba(37, 99, 235, 0.4);
}
23 changes: 21 additions & 2 deletions app/components/Layout/Footer/index.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import React, { useMemo } from "react";
"use client";
import React, { useMemo, useEffect } from "react";
import "./Footer.css";
import { FaLinkedinIn, FaGithub } from "react-icons/fa";
import { BsTwitterX } from "react-icons/bs";

const Footer = () => {
const currentYear = useMemo(() => new Date().getFullYear(), []);

useEffect(() => {
const interval = setInterval(() => {
if (typeof window !== "undefined" && window.SocialShareButton) {
new window.SocialShareButton({
container: "#share-button",
url: "https://aossie.org",
title: "Check out AOSSIE!"
Comment on lines +15 to +16
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Share payload is hardcoded to a different site.

The widget currently shares https://aossie.org instead of the active Resonate page. Use runtime page metadata (window.location.href, document.title) so shares reflect what the user is viewing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/Layout/Footer/index.jsx` around lines 15 - 16, The share
payload in Layout/Footer/index.jsx currently hardcodes url: "https://aossie.org"
and title: "Check out AOSSIE!" so shares point to the wrong site; locate the
share payload object in the Footer component and replace those hardcoded values
with runtime page metadata (use window.location.href and document.title),
guarding for SSR by checking typeof window !== 'undefined' and falling back to
sensible defaults (e.g., site home URL and a default title) so the share uses
the current page URL and title when available.

});
clearInterval(interval);
}
}, 300);
return () => clearInterval(interval);
}, []);
Comment on lines +10 to +22
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Polling is unbounded if the external script never becomes available.

If window.SocialShareButton never loads, the interval keeps running for the component lifetime. Add a retry cap/timeout and fail fast.

Proposed reliability fix
 useEffect(() => {
-  const interval = setInterval(() => {
+  let attempts = 0;
+  const maxAttempts = 20; // ~6s at 300ms
+  const interval = setInterval(() => {
+    attempts += 1;
     if (typeof window !== "undefined" && window.SocialShareButton) {
       new window.SocialShareButton({
         container: "#share-button",
         url: "https://aossie.org", 
         title: "Check out AOSSIE!"
       });
       clearInterval(interval);
+      return;
     }
+    if (attempts >= maxAttempts) clearInterval(interval);
   }, 300);
   return () => clearInterval(interval);
 }, []);
📝 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
useEffect(() => {
const interval = setInterval(() => {
if (typeof window !== "undefined" && window.SocialShareButton) {
new window.SocialShareButton({
container: "#share-button",
url: "https://aossie.org",
title: "Check out AOSSIE!"
});
clearInterval(interval);
}
}, 300);
return () => clearInterval(interval);
}, []);
useEffect(() => {
let attempts = 0;
const maxAttempts = 20; // ~6s at 300ms
const interval = setInterval(() => {
attempts += 1;
if (typeof window !== "undefined" && window.SocialShareButton) {
new window.SocialShareButton({
container: "#share-button",
url: "https://aossie.org",
title: "Check out AOSSIE!"
});
clearInterval(interval);
return;
}
if (attempts >= maxAttempts) clearInterval(interval);
}, 300);
return () => clearInterval(interval);
}, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/Layout/Footer/index.jsx` around lines 10 - 22, The useEffect
polling loop that creates new window.SocialShareButton (uses interval variable
inside useEffect) can run indefinitely if the external script never loads;
modify the effect to add a retry cap and a timeout: track attempts (e.g.,
maxAttempts) or an elapsed start time inside the effect, increment attempts each
tick and clearInterval(interval) and stop trying once the cap/time is reached,
and optionally log or show a failure; keep the existing creation code that
instantiates new window.SocialShareButton({ container: "#share-button", url:
"...", title: "..." }) but only call it when window.SocialShareButton exists and
ensure cleanup still clears the interval in all terminal cases.


return (
<footer className="footer">
<div className="footer-container">
<div className="copyright">&copy; {currentYear}</div>

<div className="footer-socials">
<a
href="https://github.com/AOSSIE-Org"
Expand All @@ -36,9 +52,12 @@ const Footer = () => {
<FaLinkedinIn />
</a>
</div>

{/* 🔥 Share Button */}
<div id="share-button" style={{ marginTop: "1rem" }}></div>
</div>
</footer>
);
};

export default React.memo(Footer);
export default React.memo(Footer);
18 changes: 17 additions & 1 deletion app/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Raleway } from "next/font/google";
import "./globals.css";
import NavBar from "./components/Layout/NavBar";
import Footer from "./components/Layout/Footer";
import Script from "next/script";

const raleway = Raleway({
subsets: ["latin"],
Expand All @@ -25,11 +26,26 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
{/* ✅ SocialShareButton CSS */}
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"
/>
Comment on lines +31 to +34
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

css_url="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"
js_url="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js"

for url in "$css_url" "$js_url"; do
  echo "URL: $url"
  hash=$(curl -fsSL "$url" | openssl dgst -sha384 -binary | openssl base64 -A)
  echo "integrity=\"sha384-$hash\""
  echo
done

Repository: AOSSIE-Org/Resonate-Website

Length of output: 327


🏁 Script executed:

cat -n app/layout.js | sed -n '25,55p'

Repository: AOSSIE-Org/Resonate-Website

Length of output: 905


🏁 Script executed:

# Search for all external CDN links in the layout file
rg 'href=|src=' app/layout.js -A 2 -B 1

Repository: AOSSIE-Org/Resonate-Website

Length of output: 406


🏁 Script executed:

# Try to fetch the CSS/JS files and generate SRI using Python
python3 << 'EOF'
import hashlib
import base64
import urllib.request

urls = [
    "https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css",
    "https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js"
]

for url in urls:
    try:
        with urllib.request.urlopen(url, timeout=10) as response:
            content = response.read()
            hash_obj = hashlib.sha384(content)
            integrity = "sha384-" + base64.b64encode(hash_obj.digest()).decode('ascii')
            print(f"URL: {url}")
            print(f'integrity="{integrity}"')
            print()
    except Exception as e:
        print(f"Error fetching {url}: {e}")
        print()
EOF

Repository: AOSSIE-Org/Resonate-Website

Length of output: 555


🌐 Web query:

Next.js Script component integrity attribute SRI support

💡 Result:

The Next.js Script component (next/script) does not have a built-in integrity prop listed in the official documentation. Official docs for Script component props include src, strategy, onLoad, onReady, onError, etc., but no integrity. However, it supports additional arbitrary HTML attributes (like nonce, data-), which are forwarded to the underlying <script> element. You can manually add integrity="sha256-..." to external third-party scripts for SRI support. Next.js has experimental.sri support (next.config.js: experimental: { sri: { algorithm: 'sha256' } }) that automatically adds integrity attributes to its own internal static chunks (e.g., _next/static/chunks/) in App Router builds, generating a subresource-integrity-manifest.json. This works for Node.js and Edge runtimes but has limitations: missing for some client chunks ('use client'), stylesheets, and mismatches with CDN compression (open issues as of 2026). It does not apply to Script component-loaded third-party scripts. For complete SRI: - Manual for third-party via Script: <Script src="..." integrity="sha256-ABC123" crossorigin="anonymous" /> - Automatic (experimental, incomplete) for Next.js bundles via config.

Citations:


Add SRI integrity attributes to third-party CDN assets.

External CSS and JavaScript from jsdelivr are loaded without integrity verification, creating a supply-chain risk. Add integrity attributes (with corresponding SRI hash) and crossOrigin="anonymous" to both the <link> tag (lines 31-34) and the <Script> component (lines 43-46). The Next.js <Script> component supports arbitrary HTML attributes, so integrity can be passed directly:

Example for Script component
<Script
  src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js"
  integrity="sha384-[hash-here]"
  crossOrigin="anonymous"
  strategy="afterInteractive"
/>

Generate SRI hashes using: curl -s <url> | sha384sum | xxd -r -p | base64

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/layout.js` around lines 31 - 34, The external jsDelivr assets are missing
SRI and crossorigin attributes; update the <link> element that loads
"https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.css"
and the Next.js <Script> component that loads the matching .js to include
integrity="sha384-<calculated-hash>" and crossOrigin="anonymous". Generate the
SRI value by downloading each asset and computing the base64 sha384 digest (curl
-s <url> | sha384sum | xxd -r -p | base64) and plug that result into the
integrity attribute, keeping the same src and strategy props on the <Script>
component.

</head>

<body className={raleway.className}>
<NavBar />
{children}
<Footer />

{/* ✅ Load JS */}
<Script
src="https://cdn.jsdelivr.net/gh/AOSSIE-Org/SocialShareButton@v1.0.3/src/social-share-button.js"
strategy="afterInteractive"
/>

</body>
</html>
);
}
}