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
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,15 @@ This project uses **React.js**.

```

6. Start development server
6. Configure frontend API base URL
Create a frontend env var so the contact form knows where to send requests:

```bash
# create a .env file in the project root (same level as package.json)
echo "VITE_API_BASE_URL=http://localhost:5002" > .env
```

7. Start development server
```bash
npm run dev

Expand Down
10 changes: 8 additions & 2 deletions backend/contact.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@ const cors = require('cors');
require('dotenv').config();

const app = express();
const PORT = process.env.PORT;
const PORT = process.env.PORT || 5002;

// CORS setup
const allowedOrigin = process.env.CORS_ORIGIN || 'http://localhost:5173';
app.use(cors({
origin: 'http://localhost:5173',
origin: allowedOrigin,
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type'],
}));

app.use(express.json());

// Health check
app.get('/health', (_req, res) => {
res.status(200).json({ status: 'ok' });
});

const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
Expand Down
4 changes: 3 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.png" type="image/png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="canonical" href="https://osk-open-source.netlify.app/" />
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.

⚠️ Potential issue | 🟠 Major

Canonical URL should be dynamic per route.

The hardcoded canonical URL will incorrectly apply to all routes (/contact, /programs, etc.), causing all pages to declare the homepage as canonical. This harms SEO by preventing proper indexing of individual pages.

Consider using a dynamic solution:

  • For React apps, use a library like react-helmet or react-helmet-async to set canonical URLs per route.
  • Alternatively, handle this at build/deployment time if using SSG/SSR.

Example with react-helmet:

// In each page component
import { Helmet } from 'react-helmet-async';

<Helmet>
  <link rel="canonical" href={`https://osk-open-source.netlify.app${location.pathname}`} />
</Helmet>
🤖 Prompt for AI Agents
In index.html around line 27 the canonical link is hardcoded to the homepage
which makes every route report the same canonical URL; remove this static tag
from the global HTML and instead generate a per-route canonical URL at runtime
or build time — for a React app add canonical tags in each page component (e.g.,
via react-helmet or react-helmet-async) using the current pathname to build the
absolute URL, or if using SSG/SSR emit the canonical during page generation;
ensure the canonical is the full absolute URL and handle trailing slashes/params
consistently.

<meta name="theme-color" content="#0ea5e9" />
<title>OSK</title>
</head>
<body>
<a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 bg-white text-black px-3 py-2 rounded">Skip to content</a>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
Expand Down
5 changes: 5 additions & 0 deletions public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
User-agent: *
Allow: /

Sitemap: https://osk-open-source.netlify.app/sitemap.xml

26 changes: 26 additions & 0 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://osk-open-source.netlify.app/</loc>
<priority>1.0</priority>
</url>
<url>
<loc>https://osk-open-source.netlify.app/programs</loc>
</url>
<url>
<loc>https://osk-open-source.netlify.app/mentors</loc>
</url>
<url>
<loc>https://osk-open-source.netlify.app/contributors</loc>
</url>
<url>
<loc>https://osk-open-source.netlify.app/community</loc>
</url>
<url>
<loc>https://osk-open-source.netlify.app/learning</loc>
</url>
<url>
<loc>https://osk-open-source.netlify.app/contact</loc>
</url>
</urlset>

6 changes: 5 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import CommunityPage from "./pages/CommunityPage";
import LearningTrack from "./pages/LearningTrack";
import ModuleDetail from "./pages/ModuleDetail";
import BackToTop from "./components/shared/BackToTop";
import Contact from "./components/Contact_Form/Contact";
import NotFound from "./pages/NotFound";

export default function App() {
return (
Expand All @@ -30,7 +32,7 @@ export default function App() {
<div className="min-h-screen flex flex-col bg-gradient-to-br from-gray-100 to-indigo-50 dark:from-gray-900 dark:to-gray-800">
<Navbar />

<main className="pt-24">
<main id="main-content" className="pt-24">
{/* Routed pages */}
<Routes>
<Route path="/" element={<Home />} />
Expand All @@ -40,6 +42,8 @@ export default function App() {
<Route path="/community" element={<CommunityPage />} />
<Route path="/learning" element={<LearningTrack />} />
<Route path="/learning/:trackId/:moduleId" element={<ModuleDetail />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} />
</Routes>
</main>

Expand Down
3 changes: 2 additions & 1 deletion src/components/Contact_Form/Contact.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export default function Contact() {
setStatus('Sending...');

try {
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5002';
console.log('Sending request to backend...');
const response = await fetch('http://localhost:5002/api/contact', {
const response = await fetch(`${apiBaseUrl}/api/contact`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
Expand Down
14 changes: 14 additions & 0 deletions src/components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ const Navbar = () => {
>
Learning
</Link>
<Link
to="/contact"
className={`${isActive("/contact") === "nav-link active" ? "text-blue-700 dark:text-blue-400 bg-blue-500/12 dark:bg-blue-400/12" : "text-gray-900 dark:text-gray-100"} no-underline font-medium py-2 px-4 rounded-lg transition-all duration-300 relative`}
onClick={() => setIsMenuOpen(false)}
>
Contact
</Link>

<a
href="https://github.com/Open-Source-Kashmir"
Expand Down Expand Up @@ -183,6 +190,13 @@ const Navbar = () => {
>
Learning
</Link>
<Link
to="/contact"
className={`${isActive("/contact") === "nav-link active" ? "text-blue-700 dark:text-blue-400 bg-blue-50 dark:bg-blue-950/40 border-l-4 border-blue-700 dark:border-blue-400" : "text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800/50"} no-underline font-medium py-2.5 sm:py-3 px-3 sm:px-4 rounded-lg transition-all duration-200 block text-sm sm:text-base`}
onClick={() => setIsMenuOpen(false)}
>
Contact
</Link>
</div>

{/* Divider */}
Expand Down
21 changes: 21 additions & 0 deletions src/pages/NotFound.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Link } from 'react-router-dom'

export default function NotFound() {
return (
<div className="min-h-[60vh] flex flex-col items-center justify-center text-center px-6">
<p className="text-sm font-semibold text-blue-600">404</p>
<h1 className="mt-2 text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-100">Page not found</h1>
<p className="mt-2 text-base text-gray-600 dark:text-gray-300">Sorry, we couldn’t find the page you’re looking for.</p>
<div className="mt-6 flex items-center gap-4">
<Link to="/" className="no-underline bg-blue-600 hover:bg-blue-700 text-white px-5 py-2.5 rounded-lg transition">
Go back home
</Link>
<Link to="/community" className="no-underline text-blue-700 dark:text-blue-400 hover:underline">
Visit community
</Link>
</div>
</div>
)
}