-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #407 from Sawan-Kushwah/centralized/projectShowcase
Implemented frontend and backend Project Showcase with Repository Integration
- Loading branch information
Showing
9 changed files
with
330 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.