Skip to content

Commit

Permalink
Merge pull request #447 from Sawan-Kushwah/add/stories
Browse files Browse the repository at this point in the history
Build frontend and Backend for Stories Page: Implement POST and GET Routes | clean schema✨🚀
  • Loading branch information
Jaishree2310 authored Nov 11, 2024
2 parents 49ab3f4 + 1074b08 commit 21c2bc4
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 1 deletion.
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<title>GlassyUI</title>
</head>

<body>
<body style="background-color: #17202e;">


<!-- Root element for React to render into -->
Expand Down
8 changes: 8 additions & 0 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import dotenv from 'dotenv';
import connectDB from './utils/db.js';
import cors from 'cors';
import contactRoutes from './routes/contactRoutes.js';

import stories from './routes/storiesRoutes.js';

import newsletterRoutes from './routes/newsletterRoute.js';


dotenv.config();
const app = express();
connectDB();
Expand All @@ -19,8 +23,12 @@ app.use(

// Serve static files from the uploads directory
app.use('/api/contact', contactRoutes);

app.use('/api/stories', stories);

app.use('/api/newsletter', newsletterRoutes);


const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
Expand Down
25 changes: 25 additions & 0 deletions server/controllers/postsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// postsController.js
import Post from '../model/postModel.js';

// Fetch all posts
export const getPosts = async (req, res) => {
try {
const posts = await Post.find();
res.status(200).json(posts);
} catch (error) {
res.status(500).json({ message: 'Error fetching posts', error });
}
};

// Save a new post
export const savePost = async (req, res) => {
const { title, content, category, date } = req.body;

try {
const newPost = new Post({ title, content, category, date });
const savedPost = await newPost.save();
res.status(201).json(savedPost);
} catch (error) {
res.status(500).json({ message: 'Error saving post', error });
}
};
13 changes: 13 additions & 0 deletions server/model/postModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// postModel.js
import mongoose from 'mongoose';

const postSchema = new mongoose.Schema({
title: String,
content: String,
category: String,
date: { type: Date, default: Date.now },
});

const Post = mongoose.model('Post', postSchema);

export default Post;
9 changes: 9 additions & 0 deletions server/routes/storiesRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express from 'express';
import { getPosts, savePost } from '../controllers/postsController.js';

const router = express.Router();

router.get('/getposts', getPosts);
router.post('/saveposts', savePost);

export default router;
6 changes: 6 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import ProductCardDetailsPage from './components/ProductCardDetailsPage';
import ContactUs from './components/ContactUs';
import AiChatbot from './components/AIChatbot';
import { TermsOfUse } from './components/TermsOfUse';

import Stories from './components/Stories';
import Register from './login/SignUp';
import SignIn from './login/SignIn';

Expand Down Expand Up @@ -120,8 +122,12 @@ const App: React.FC = () => {
<Route path='/gallery-details' element={<GalleryDetailsPage />} />
<Route path='/contact' element={<ContactUs />} />
<Route path='/termsOfUse' element={<TermsOfUse />} />

<Route path='/stories' element={<Stories />} />

<Route path='/signup' element={<Register />} />
<Route path='/signin' element={<SignIn />} />

<Route path='*' element={<NotFoundPage />} />
</Routes>
<ConditionalFooter />
Expand Down
10 changes: 10 additions & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ const Header: React.FC = () => {
Contact Us
</Link>
</li>
<li style={liStyle} className='navbar-item'>
<Link
to='/stories'
style={linkStyle}
onMouseEnter={e => (e.currentTarget.style.color = '#fde047')}
onMouseLeave={e => (e.currentTarget.style.color = 'white')}
>
Stories
</Link>
</li>
</ul>
{userLoggedIn && currentUser ? (
<UserAccount
Expand Down
182 changes: 182 additions & 0 deletions src/components/Stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import React, { useState, useEffect } from 'react';

interface Post {
title: string;
content: string;
category: string;
date: string;
}

const Stories = () => {
const [posts, setPosts] = useState<Post[]>([]);
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [category, setCategory] = useState('');

useEffect(() => {
// Fetch posts from the backend API
const fetchPosts = async () => {
try {
const response = await fetch(
'http://localhost:5000/api/stories/getposts',
);
if (response.ok) {
const data = await response.json();
setPosts(data);
} else {
console.error('Failed to fetch posts');
}
} catch (error) {
console.error('Error fetching posts:', error);
}
};

fetchPosts();
}, []);

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

if (title && content && category) {
const newPost = {
title,
content,
category,
date: new Date().toISOString(),
};

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

if (response.ok) {
const savedPost = await response.json();
setPosts([savedPost, ...posts]); // Add the new post to state
} else {
console.error('Failed to save the post');
}
} catch (error) {
console.error('Error saving the post:', error);
}

// Clear form fields
setTitle('');
setContent('');
setCategory('');
}
};

return (
<>
<h1 className='text-3xl font-bold text-center mb-5 text-gray-100 mt-20'>
Real Stories, Real Advice: Share Your Experience
</h1>

<div className='flex flex-col lg:flex-row items-start gap-8 px-6 lg:px-20 mb-14'>
{/* Left side - Posts */}
<div className='flex-1 space-y-6'>
{posts.length === 0 ? (
<p className='text-gray-400 text-center'>
No posts yet. Share your experience!
</p>
) : (
posts.map((post, index) => (
<div
key={index}
className='bg-gray-800 text-white shadow-lg rounded-xl p-8 border border-gray-700 hover:shadow-xl transition-all duration-300 ease-in-out'
>
<h3 className='text-2xl font-bold text-gray-100 mb-2'>
{post.title}
</h3>
<p className='text-sm text-indigo-400 font-medium mb-6'>
{post.category}
</p>
<p className='text-gray-300 leading-relaxed mb-4'>
{post.content}
</p>
<div className='flex items-center justify-between'>
<p className='text-xs text-gray-500'>
{new Date(post.date).toLocaleDateString()}
</p>
<button className='text-indigo-500 text-sm font-medium border border-indigo-100 rounded-full px-4 py-1 hover:bg-indigo-700 transition-colors'>
Read More
</button>
</div>
</div>
))
)}
</div>

{/* Right side - Form */}
<div className='w-full lg:w-1/3 bg-gray-800 p-6 rounded-lg shadow-md'>
<form className='space-y-4'>
<input
type='text'
placeholder='Title of your story'
value={title}
onChange={e => setTitle(e.target.value)}
className='w-full p-3 rounded-md border border-gray-600 bg-gray-700 text-white focus:outline-none focus:border-blue-500'
/>
<textarea
placeholder='Write about your story...'
value={content}
onChange={e => setContent(e.target.value)}
className='w-full p-3 h-32 rounded-md border border-gray-600 bg-gray-700 text-white focus:outline-none focus:border-blue-500'
></textarea>
<select
value={category}
onChange={e => setCategory(e.target.value)}
className='block w-full px-4 py-2 bg-gray-700 text-white border border-gray-600 rounded-md shadow-sm focus:border-indigo-500 focus:ring-indigo-500'
>
<option value='' disabled>
Select Category
</option>

<optgroup label='GlassyUI-Components'>
<option value='GlassyUI Introduction'>
GlassyUI Introduction
</option>
<option value='Customizing GlassyUI Components'>
Customizing GlassyUI Components
</option>
<option value='Advanced GlassyUI Techniques'>
Advanced GlassyUI Techniques
</option>
<option value='GlassyUI Best Practices'>
GlassyUI Best Practices
</option>
<option value='Contributing to GlassyUI'>
Contributing to GlassyUI
</option>
<option value='React and GlassyUI Integration'>
React and GlassyUI Integration
</option>
<option value='GlassyUI in Real Projects'>
GlassyUI in Real Projects
</option>
<option value='GlassyUI Updates'>GlassyUI Updates</option>
</optgroup>
</select>

<button
onClick={handleSubmit}
className='w-full bg-blue-500 hover:bg-blue-600 hover:text-white text-white font-semibold py-2 rounded-md focus:outline-none'
>
Post Experience
</button>
</form>
</div>
</div>
</>
);
};

export default Stories;

0 comments on commit 21c2bc4

Please sign in to comment.