Skip to content

Commit

Permalink
Merge pull request #550 from VinayLodhi1712/newsletter
Browse files Browse the repository at this point in the history
newsletter frontend and backend done : #542 done
  • Loading branch information
Luson045 authored Oct 28, 2024
2 parents 69a6bf8 + 2f79cf7 commit 130bbb1
Show file tree
Hide file tree
Showing 13 changed files with 10,350 additions and 15,022 deletions.
25,000 changes: 10,001 additions & 14,999 deletions client/package-lock.json

Large diffs are not rendered by default.

66 changes: 63 additions & 3 deletions client/src/components/Footer.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
// import playstore from "../assets/favicon2.png";
import {
FaGithub,
Expand All @@ -18,6 +18,10 @@ const Footer = () => {
const currentYear = new Date().getFullYear();
const [showScrollTop, setShowScrollTop] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const [messageType, setMessageType] = useState('');
const navigate = useNavigate();

const handleScroll = () => {
if (window.scrollY > 200) {
Expand All @@ -41,6 +45,36 @@ const Footer = () => {
};
}, []);

const handleSubscribe = async () => {
try {
const response = await fetch('http://localhost:8080/otherroutes/subscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
});
if (response.ok) {
setMessage('Subscription successful! Confirmation mail sent');
setMessageType('success');
setEmail('');
} else {
setMessage('Subscription failed. Try again.');
setMessageType('error');
}
setTimeout(() => {
setMessage('');
setEmail('');
}, 5000); // Clear the message and input after 5 seconds
} catch (error) {
console.error('Subscription error:', error);
setMessage('An error occurred. Please try again later.');
setMessageType('error');

setTimeout(() => setMessage(''), 5000);
}
};

// Define company links with distinct paths
const aboutLinks = [
{ name: 'Our Hospital', path: '/our-hospital' },
Expand Down Expand Up @@ -72,6 +106,7 @@ const Footer = () => {
{ name: 'Business', path: '/business' },
{ name: 'Support Us', path: '/support-us' },
{ name: 'Customer Care', path: '/customer-care' },
{ name: 'Newsletter', path: '/newsletter-dashboard' },
];

// const handleRating = (value) => {
Expand All @@ -88,6 +123,31 @@ const Footer = () => {
return (
<footer className="bg-gradient-to-r from-[#b6dbfc] via-[#8faed9] to-[#b6dbfc] p-8 text-white shadow-lg shadow-black">
<div className="container mx-auto">
{/* Newsletter Subscription Section */}
<div className="text-center md:col-span-2 lg:col-span-4 my-4">
<h3 className="text-2xl font-semibold mb-4">Subscribe to our Newsletter</h3>
<div className="flex flex-col md:flex-row justify-center items-center gap-2 md:gap-4">
<input
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="p-2 rounded border border-gray-300 text-black w-full max-w-[300px]"
/>
<button
onClick={handleSubscribe}
className="bg-blue-600 hover:bg-blue-700 text-white p-2 rounded w-full max-w-[150px]"
>
Subscribe
</button>
</div>
{message && (
<p className={`text-2xl mt-2 ${messageType === 'success' ? 'text-green-500' : 'text-red-500'}`}>
{message}
</p>
)}
</div>

<div className="flex flex-wrap justify-between space-x-4">
{/* Med Space Section */}
<div className="space-y-4 w-full md:w-auto">
Expand Down Expand Up @@ -279,8 +339,8 @@ const Footer = () => {
</button>
</div>
</div>
</footer>
</footer >
);
};

export default Footer;
export default Footer;
6 changes: 4 additions & 2 deletions client/src/components/Layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import HospitalAppointments from '../pages/HospitalPanal';
import BusinessContactForm from "./BusinessContactForm";
import ForgotPassword from "./ForgotPassword";
import PrivateRoute from '../privateroute/privateroute';

import Newsletters from '../pages/Newsletters';

function Layout() {
const location = useLocation();
Expand All @@ -49,7 +49,8 @@ function Layout() {
path === '/Labtest' ||
path === '/blog' ||
path === '/business'||
path === '/forgot-password'
path === '/forgot-password'||
path === '/newsletter-dashboard'
) {
showNavAndFooter = true;
}
Expand Down Expand Up @@ -96,6 +97,7 @@ function Layout() {
<Route path="/business" element={<BusinessContactForm />}></Route>
<Route path="/not-found" element={<NotFound />} />
<Route path="*" element={<Navigate to="/not-found" />} />
<Route path="/newsletter-dashboard" element={<Newsletters/>} />
</Routes>
</div>
<Chatbot />
Expand Down
98 changes: 98 additions & 0 deletions client/src/pages/Newsletters.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useState, useEffect, useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import { UserContext } from '../store/userContext'; // Import the UserContext

const Newsletters = () => {
const { user, isAuthenticated, loading } = useContext(UserContext); // Access user and loading from UserContext
const navigate = useNavigate();

// Redirect if not admin or not authenticated
useEffect(() => {
if (!loading && (!isAuthenticated || !user?.isAdmin)) {
navigate('/login'); // Redirect to login page if not admin
}
}, [isAuthenticated, user, loading, navigate]);

const [subject, setSubject] = useState('');
const [message, setMessage] = useState('');
const [status, setStatus] = useState('');

const handleSendNewsletter = async () => {
try {
const credentials = btoa(`${user.email}:${user.password}`);

const response = await fetch('http://localhost:8080/otherroutes/admin/send-mail', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${credentials}`,
},
body: JSON.stringify({ subject, message }),
});

const result = await response.json();
setStatus(response.ok ? { type: 'success', message: result.message } : { type: 'error', message: result.message });

// Clear inputs and status message after 7 seconds
setTimeout(() => {
setSubject('');
setMessage('');
setStatus('');
}, 7000); // 7 seconds in milliseconds
} catch (error) {
setStatus({ type: 'error', message: 'An error occurred. Please try again.' });

// Clear the error message after 7 seconds
setTimeout(() => {
setStatus('');
}, 7000);
}
};

// Show loading message if user data is still being fetched
if (loading) return <p>Loading...</p>;

return isAuthenticated && user?.isAdmin ? (
<div className="flex flex-col items-center p-6 bg-gray-100 min-h-screen mt-10">
<div className="w-full max-w-2xl bg-white shadow-lg rounded-lg p-6">
<h2 className="text-2xl font-bold text-center mb-6">Newsletter Dashboard</h2>

<div className="mb-4">
<label className="block text-gray-700 font-semibold mb-2">Subject</label>
<input
type="text"
placeholder="Enter the subject"
value={subject}
onChange={(e) => setSubject(e.target.value)}
className="w-full p-3 border border-gray-300 rounded focus:outline-none focus:border-blue-500"
/>
</div>

<div className="mb-4">
<label className="block text-gray-700 font-semibold mb-2">Message</label>
<textarea
placeholder="Write your message here"
value={message}
onChange={(e) => setMessage(e.target.value)}
className="w-full h-32 p-3 border border-gray-300 rounded resize-none focus:outline-none focus:border-blue-500"
/>
</div>

<button
onClick={handleSendNewsletter}
className="w-full bg-blue-600 text-white p-3 rounded hover:bg-blue-700 transition duration-300"
>
Send Newsletter
</button>

{status && (
<div className={`mt-4 p-3 rounded ${status.type === 'success' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>
{status.message}
</div>
)}
</div>
</div>
) : null;
};

export default Newsletters;
30 changes: 12 additions & 18 deletions client/src/store/userContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,26 @@ export const UserProvider = ({ children }) => {
const token = localStorage.getItem('token');

if (!token) {
// If no token, consider the user as not authenticated
setAuth(false);
setUser(null);
setLoading(false); // Stop loading when no token is found
setLoading(false);
return;
}

const response = await fetch(
databaseUrls.auth.profile,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
'x-auth-token': token,
},

const response = await fetch(databaseUrls.auth.profile, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'x-auth-token': token,
},
);

});
if (response.ok) {
const data = await response.json();
localStorage.setItem('userid', data._id); // Store user ID if needed elsewhere
setUser(data);
localStorage.setItem('userid', data._id);
setUser(data); // `data` should include `isAdmin` from backend if user is an admin
setAuth(true);
} else {
// Handle cases where token might be invalid or expired
setAuth(false);
setUser(null);
localStorage.removeItem('token');
Expand All @@ -53,9 +48,8 @@ export const UserProvider = ({ children }) => {
setAuth(false);
setUser(null);
}
setLoading(false); // Stop loading once profile fetch is complete
setLoading(false);
};

useEffect(() => {
fetchProfile();
}, [location.pathname]); // Refetch profile when location changes or on refresh
Expand Down
12 changes: 12 additions & 0 deletions server/.env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
JWT_SECRET="Anmol"
OPENCAGE_API_KEY="212deee1820f49ae8bef1cb927434363"
MONGO_URI="mongodb://localhost:27017/mediconnect"

#your email of which you are using the passkey
SMTP_EMAIL="{}"

# To create a passkey on the phone or computer you’re on:

# 1. Go to https://myaccount.google.com/signinoptions/passkeys.
# 2. Tap Create a passkey and then Continue.(You'll be required to unlock your device.)
# 3. A 16 character passkey is generated which you can use in below.

SMTP_PASSWORD="{}"
SMTP_PORT=465

#from which you want to send the email to users
SMTP_HOST="{}"

PORT = 8080
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
Loading

0 comments on commit 130bbb1

Please sign in to comment.