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
123 changes: 72 additions & 51 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// src/App.jsx
import { Routes, Route, Navigate, NavLink } from "react-router-dom";
import { Fragment } from "react";
import ProtectedRoute from "./auth/ProtectedRoute";
import { useAuth } from "./auth/AuthContext";

Expand All @@ -22,71 +23,91 @@ export default function App() {
{/* Navbar */}
<nav className="navbar">
<div className="navbar-inner">
<div className="brand">SyncSkilled</div>
<div className="nav-links">
<NavLink
to="/"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
Home
</NavLink>
<NavLink
to="posts"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
{" "}
Posts
</NavLink>
<div className="flex flex-col gap-1">
<span className="brand">SyncSkilled</span>
<span className="text-xs uppercase tracking-[0.35em] text-slate-500">
Learn • Share • Grow
</span>
</div>

{user && (
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between md:flex-1 md:pl-8">
<div className="nav-links">
<NavLink
to="/"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
end
>
Home
</NavLink>
<NavLink
to="/catalog"
to="/posts"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
Catalog
Posts
</NavLink>
)}

{user ? (
<>
<NavLink
to="/me"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
Profile
</NavLink>
<button className="btn-primary" onClick={logout}>
Logout
</button>
</>
) : (
<>
<NavLink
to="/login"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
Login
</NavLink>
{user && (
<NavLink
to="/register"
to="/catalog"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
Register
Catalog
</NavLink>
</>
)}
)}
</div>

<div className="nav-cta">
{user ? (
<Fragment>
<NavLink
to="/posts/create"
className={({ isActive }) =>
isActive
? "btn-primary"
: "btn-outline"
}
>
New Post
</NavLink>
<NavLink
to="/me"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
Profile
</NavLink>
<button className="btn-muted" onClick={logout}>
Logout
</button>
</Fragment>
) : (
<Fragment>
<NavLink
to="/login"
className={({ isActive }) =>
isActive ? "nav-link nav-link-active" : "nav-link"
}
>
Login
</NavLink>
<NavLink
to="/register"
className={({ isActive }) =>
isActive ? "btn-primary" : "btn-outline"
}
>
Join now
</NavLink>
</Fragment>
)}
</div>
</div>
</div>
</nav>
Expand Down
192 changes: 138 additions & 54 deletions src/pages/CreatePost.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { usePosts } from "../context/PostContext";

export default function CreatePost({ onCreated }) {
const { createPost } = usePosts();
const navigate = useNavigate();

const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [skillToLearn, setSkillToLearn] = useState("");
const [skillToTeach, setSkillToTeach] = useState("");
const [exchangeCredits, setExchangeCredits] = useState(1);
const [location, setLocation] = useState("");
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);

Expand All @@ -22,13 +26,15 @@ export default function CreatePost({ onCreated }) {
skillToLearn,
skillToTeach,
exchangeCredits,
location,
});
onCreated?.(newPost); // optional callback to parent
setTitle("");
setDescription("");
setSkillToLearn("");
setSkillToTeach("");
setExchangeCredits(1);
onCreated?.(newPost);
const targetId = newPost?._id;
if (targetId) {
navigate(`/posts/${targetId}`);
} else {
navigate("/posts");
}
} catch (err) {
setError(err.message || "Error creating post");
} finally {
Expand All @@ -37,54 +43,132 @@ export default function CreatePost({ onCreated }) {
};

return (
<form
onSubmit={handleSubmit}
style={{
padding: "20px",
border: "1px solid #ccc",
borderRadius: "10px",
}}
>
<h2>Create a New Post</h2>
{error && <p style={{ color: "red" }}>{error}</p>}
<input
type="text"
placeholder="Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
<textarea
placeholder="Description"
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
<input
type="text"
placeholder="Skill to Learn"
value={skillToLearn}
onChange={(e) => setSkillToLearn(e.target.value)}
required
/>
<input
type="text"
placeholder="Skill to Teach"
value={skillToTeach}
onChange={(e) => setSkillToTeach(e.target.value)}
required
/>
<input
type="number"
placeholder="Exchange Credits"
value={exchangeCredits}
min={1}
max={9999}
onChange={(e) => setExchangeCredits(Number(e.target.value))}
required
/>
<button type="submit" disabled={loading}>
{loading ? "Creating..." : "Create Post"}
<div className="grid gap-6">
<button className="btn-ghost justify-start w-fit" onClick={() => navigate(-1)}>
← Back
</button>
</form>

<section className="section-card">
<header className="grid gap-2">
<span className="section-title">Share a new exchange</span>
<h1 className="heading text-3xl font-bold">Craft a post that invites collaboration</h1>
<p className="text-sm text-slate-600 max-w-2xl">
Highlight what you’d love to learn, what you can teach in return, and any context that helps
the community understand your goals.
</p>
</header>

<form className="form" onSubmit={handleSubmit}>
{error && (
<div className="rounded-2xl border border-red-100 bg-red-50 px-4 py-3 text-sm font-medium text-red-600">
{error}
</div>
)}

<div className="field-row">
<label htmlFor="title" className="label">
Post title
</label>
<input
id="title"
type="text"
className="input"
placeholder="e.g. Swap Figma tips for React mentorship"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
</div>

<div className="field-row">
<label htmlFor="description" className="label">
Description
</label>
<textarea
id="description"
className="textarea"
placeholder="Share what you’re aiming to learn, your availability, and how you love to collaborate."
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
</div>

<div className="grid gap-4 md:grid-cols-2">
<div className="field-row">
<label htmlFor="skillToLearn" className="label">
Skill to learn
</label>
<input
id="skillToLearn"
type="text"
className="input"
placeholder="Product storytelling"
value={skillToLearn}
onChange={(e) => setSkillToLearn(e.target.value)}
required
/>
</div>
<div className="field-row">
<label htmlFor="skillToTeach" className="label">
Skill to teach
</label>
<input
id="skillToTeach"
type="text"
className="input"
placeholder="Advanced user research"
value={skillToTeach}
onChange={(e) => setSkillToTeach(e.target.value)}
required
/>
</div>
</div>

<div className="grid gap-4 md:grid-cols-2">
<div className="field-row">
<label htmlFor="exchangeCredits" className="label">
Exchange credits
</label>
<input
id="exchangeCredits"
type="number"
min={1}
max={9999}
className="input"
value={exchangeCredits}
onChange={(e) => setExchangeCredits(Number(e.target.value))}
required
/>
</div>
<div className="field-row">
<label htmlFor="location" className="label">
Location
</label>
<input
id="location"
type="text"
className="input"
placeholder="Remote or city / timezone"
value={location}
onChange={(e) => setLocation(e.target.value)}
/>
</div>
</div>

<div className="form-actions">
<button
type="button"
className="btn-muted"
onClick={() => navigate("/posts")}
>
Cancel
</button>
<button type="submit" className="btn-primary" disabled={loading}>
{loading ? "Publishing…" : "Publish post"}
</button>
</div>
</form>
</section>
</div>
);
}
Loading