Skip to content

Commit

Permalink
Merge pull request #407 from Sawan-Kushwah/centralized/projectShowcase
Browse files Browse the repository at this point in the history
Implemented frontend and backend Project Showcase with Repository Integration
  • Loading branch information
Anuj3553 authored Nov 7, 2024
2 parents 4291092 + bdba6fb commit 48409ff
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 20 deletions.
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

0 comments on commit 48409ff

Please sign in to comment.