Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented frontend and backend Project Showcase with Repository Integration #407

Merged
Merged
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 client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import "aos/dist/aos.css";
import Collab from "./component/Collab";
import FAQ from "./component/Faq";
import CreateBlog from "./component/CreateBlog";
import Projects from "./component/Projects";
import UploadProject from "./component/UploadProject";

// Main Layout Component
const Layout = ({ children, mode, setProgress, toggleMode, showAlert }) => {
Expand All @@ -53,6 +55,7 @@ const Layout = ({ children, mode, setProgress, toggleMode, showAlert }) => {
blog="Blogs"
discussion="Discussion"
contributors="Contributors"
projects="Projects"
Feedback="Feedback"
showAlert={showAlert}
mode={mode}
Expand Down Expand Up @@ -147,6 +150,8 @@ function App() {
<Route exact path='/contactus' element={<ContactUs mode={mode} setProgress={setProgress} showAlert={showAlert} />} />
<Route exact path='/privacypolicy' element={<PrivacyPolicy mode={mode} setProgress={setProgress} showAlert={showAlert} />} />
<Route exact path='/termofuse' element={<TermOfUse mode={mode} setProgress={setProgress} showAlert={showAlert} />} />
<Route exact path='/projects' element={<Projects mode={mode} setProgress={setProgress} showAlert={showAlert} />} />
<Route exact path='/uploadProject' element={<UploadProject mode={mode} setProgress={setProgress} showAlert={showAlert} />} />
<Route exact path='/FAQ' element={<FAQ mode={mode} />} />
<Route exact path='/createBlogPost' element={<CreateBlog />} />
<Route exact path='/read-more-blog/:id' element={<ReadMoreBlog mode={mode} setProgress={setProgress} showAlert={showAlert} />} />
Expand Down
11 changes: 11 additions & 0 deletions client/src/component/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ function Navbar(props) {
{props.contributors}
</Link>
</li>
<li className="nav-item fs-6">
<Link
className={`nav-link ${location.pathname === "/projects" ? "active" : ""
}`}
aria-current="page"
to="/projects"
>
{props.projects}
</Link>
</li>
</ul>
</div>

Expand Down Expand Up @@ -590,6 +600,7 @@ Navbar.propTypes = {
blog: PropTypes.string,
about: PropTypes.string,
contributors: PropTypes.string,
projects: PropTypes.string,
profile: PropTypes.string,
mode: PropTypes.string,
toggleMode: PropTypes.func,
Expand Down
103 changes: 103 additions & 0 deletions client/src/component/Projects.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, { useState, useEffect } from 'react';
import PropTypes from "prop-types";
import { useNavigate } from 'react-router-dom';
import axios from 'axios';

const Projects = ({ mode }) => {
const navigate = useNavigate();
const [projects, setProjects] = useState([]); // State to store fetched projects
const [loading, setLoading] = useState(true); // State for loading state
const [error, setError] = useState(null); // State for error handling

useEffect(() => {
// Fetch the data from the API when the component mounts
const fetchProjects = async () => {
try {
const response = await axios.get('http://localhost:5000/api/showcaseProjects/all-projects');
setProjects(response.data); // Store the fetched projects in state
setLoading(false); // Set loading to false after data is fetched
} catch (err) {
setError('Error fetching projects');
setLoading(false); // Set loading to false if an error occurs
}
};

fetchProjects(); // Call the function to fetch data
}, []); // Empty dependency array means this effect runs once on mount

const handleButtonClick = () => {
navigate('/uploadProject');
};

if (loading) {
return <div>Loading...</div>;
}

if (error) {
return <div>{error}</div>;
}

return (
<div
className={`container mx-auto p-6 mt-32 ${mode === 'dark' ? 'bg-gray-900 text-white' : 'bg-white text-gray-900'}`}
>
<div className="relative mb-12">
<h1 className="text-4xl font-extrabold text-center tracking-tight">
Projects Showcase
</h1>
<button
className={`absolute top-0 right-0 mt-4 mr-6 ${mode === 'dark'
? 'text-white bg-gray-700 hover:bg-gray-600'
: 'text-gray-900 bg-gray-200 hover:bg-gray-300'
} px-4 py-2 rounded-md text-sm font-semibold transition-colors duration-300`}
onClick={handleButtonClick}
>
Add Project
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{projects.map((project, index) => (
<div
key={index}
className={`${mode === 'dark' ? 'bg-gray-800 text-white' : 'bg-white text-gray-900'} rounded-lg shadow-xl overflow-hidden transform hover:scale-105 hover:shadow-2xl transition-all duration-300 ease-in-out ${mode === 'dark' ? 'bg-gray-800 text-white' : 'bg-white text-gray-900'}`}
>
<div className="p-6 space-y-4">
<h2 className={`text-2xl font-semibold mb-3 ${mode === 'dark' ? 'text-white' : 'text-gray-800'}`}>
{project.title}
</h2>
<p className={`text-base ${mode === 'dark' ? 'text-gray-300' : 'text-gray-600'}`}>
{project.description}
</p>
<div className="flex justify-start space-x-4 mt-6">
<a
href={project.githubLink}
target="_blank"
rel="noopener noreferrer"
className="inline-block text-white bg-blue-600 px-4 py-2 rounded-md text-sm font-semibold hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400"
>
GitHub
</a>
{project.deploymentLink && (
<a
href={project.deploymentLink}
target="_blank"
rel="noopener noreferrer"
className="inline-block text-white bg-green-600 px-4 py-2 rounded-md text-sm font-semibold hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-400"
>
Live Demo
</a>
)}
</div>
</div>
</div>
))}
</div>
</div>
);
};

Projects.propTypes = {
mode: PropTypes.string,
};

export default Projects;
172 changes: 154 additions & 18 deletions client/src/component/UploadProject.jsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,163 @@
import '../css/UploadProject.css'
import PropTypes from 'prop-types';
import AddProject from './AddProject';
import React, { useState } from 'react';
import PropTypes from "prop-types";
import { useNavigate } from 'react-router-dom';


const UploadProject = ({ mode }) => {
const navigate = useNavigate();
const [formData, setFormData] = useState({
title: '',
description: '',
githubLink: '',
deploymentLink: '',
projectFiles: null,
});

const handleChange = (e) => {
const { name, value, type, files } = e.target;
if (type === 'file') {
setFormData((prevData) => ({
...prevData,
[name]: files[0],
}));
} else {
setFormData((prevData) => ({
...prevData,
[name]: value,
}));
}
};

const handleSubmit = async (e) => {
e.preventDefault();

try {
const response = await fetch('http://localhost:5000/api/showcaseProjects/post-project', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});

if (!response.ok) {
throw new Error('Failed to submit project');
}

const data = await response.json();
console.log('Project submitted successfully:', data);
navigate('/projects');

// Clear the form after submission
setFormData({
title: '',
description: '',
githubLink: '',
deploymentLink: '',
});

// Optionally, you can redirect the user or display a success message
} catch (error) {
console.error('Error submitting project:', error);
}
};

const themeStyles = mode === 'dark' ? 'bg-gray-800 text-white' : 'bg-white text-gray-900';

function UploadProject(props) {
return (
<div>
<div className="container">
<div className={`container mx-auto p-6 mt-40 mb-12 max-w-3xl shadow-lg rounded-lg ${themeStyles}`}>
<h1 className={`text-4xl font-bold text-center mb-8 ${mode === 'dark' ? 'text-white' : 'text-gray-900'}`}>
Upload Your Project
</h1>

<form onSubmit={handleSubmit} className="space-y-6">
{/* Project Title */}
<div>
<label htmlFor="title" className={`block text-lg font-medium ${mode === 'dark' ? 'text-gray-300' : 'text-gray-700'}`}>
Project Title
</label>
<input
type="text"
id="title"
name="title"
value={formData.title}
onChange={handleChange}
className={`w-full mt-2 p-3 border rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none ${mode === 'dark' ? 'bg-gray-700 text-white border-gray-600' : 'bg-white text-gray-900 border-gray-300'}`}
placeholder="Enter your project title"
required
/>
</div>

{/* Project Description */}
<div>
<label htmlFor="description" className={`block text-lg font-medium ${mode === 'dark' ? 'text-gray-300' : 'text-gray-700'}`}>
Project Description
</label>
<textarea
id="description"
name="description"
value={formData.description}
onChange={handleChange}
className={`w-full mt-2 p-3 border rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none ${mode === 'dark' ? 'bg-gray-700 text-white border-gray-600' : 'bg-white text-gray-900 border-gray-300'}`}
placeholder="Enter a brief description of your project"
rows="4"
required
></textarea>
</div>

{/* GitHub Link */}
<div>
<label htmlFor="githubLink" className={`block text-lg font-medium ${mode === 'dark' ? 'text-gray-300' : 'text-gray-700'}`}>
GitHub Link
</label>
<input
type="url"
id="githubLink"
name="githubLink"
value={formData.githubLink}
onChange={handleChange}
className={`w-full mt-2 p-3 border rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none ${mode === 'dark' ? 'bg-gray-700 text-white border-gray-600' : 'bg-white text-gray-900 border-gray-300'}`}
placeholder="Enter your project GitHub link"
required
/>
</div>

{/* Deployment Link */}
<div>
<label htmlFor="deploymentLink" className={`block text-lg font-medium ${mode === 'dark' ? 'text-gray-300' : 'text-gray-700'}`}>
Deployment Link (Optional)
</label>
<input
type="url"
id="deploymentLink"
name="deploymentLink"
value={formData.deploymentLink}
onChange={handleChange}
className={`w-full mt-2 p-3 border rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none ${mode === 'dark' ? 'bg-gray-700 text-white border-gray-600' : 'bg-white text-gray-900 border-gray-300'}`}
placeholder="Enter your project live demo link"
/>
</div>



{/* Submit Button */}
<div className="text-center">
<div className="body">
<h5 className="text-xl font-bold text-blue-500 mb-8">{props.title} <strong>👇</strong></h5>
<AddProject showAlert={props.showAlert} />
</div>
<button
type="submit"
className={`w-full py-3 rounded-md text-lg font-semibold ${mode === 'dark' ? 'bg-blue-700 hover:bg-blue-600' : 'bg-blue-600 hover:bg-blue-700'} text-white focus:outline-none focus:ring-2 focus:ring-blue-400`}
>
Upload Project
</button>
</div>
</div>
</form>
</div>
)
}
);
};

// Props Vadilation
UploadProject.propTypes = {
title: PropTypes.string,
desc: PropTypes.string,
showAlert: PropTypes.func,

mode: PropTypes.string,

};

export default UploadProject
export default UploadProject;
33 changes: 33 additions & 0 deletions server/Controllers/projectController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const Project = require('../Models/ProjectSchema.js');

exports.postProject = async (req, res) => {
const { title, description, githubLink, deploymentLink } = req.body;

if (!title || !description) {
return res.status(400).json({ message: 'Title and description are required' });
}

try {
const newProject = new Project({
title,
description,
githubLink,
deploymentLink,
});

await newProject.save();

return res.status(201).json({ message: 'Project created successfully', project: newProject });
} catch (error) {
return res.status(500).json({ message: 'Error creating project', error });
}
};

exports.getAllProjects = async (req, res) => {
try {
const projects = await Project.find();
return res.status(200).json(projects);
} catch (error) {
return res.status(500).json({ message: 'Error fetching projects', error });
}
};
12 changes: 12 additions & 0 deletions server/Models/ProjectSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const mongoose = require('mongoose');

const projectSchema = new mongoose.Schema({
title: { type: String, required: true },
description: { type: String, required: true },
githubLink: { type: String },
deploymentLink: { type: String },
});

const Project = mongoose.model('Project', projectSchema);

module.exports = Project;
1 change: 1 addition & 0 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ app.use("/api/feedback", require("./routes/feedback"));
app.use("/api/contact", require("./routes/contact"));
app.use("/api/blog", require("./routes/blog"));
app.use("/api/visitor", require("./routes/visitor"));
app.use("/api/showcaseProjects", require("./routes/projectsRoute"));

// Socket.io connection handling
const users = {};
Expand Down
Loading
Loading