);
-};
+}
-// Exporting the About component for use in other parts of the app
-export default About;
+export default AboutUs;
diff --git a/frontend/src/Pages/ComplainBox.jsx b/frontend/src/Pages/ComplainBox.jsx
new file mode 100644
index 0000000..5da9187
--- /dev/null
+++ b/frontend/src/Pages/ComplainBox.jsx
@@ -0,0 +1,130 @@
+import React, { useState } from 'react';
+import axios from 'axios';
+import logo from '../assets/stationsaarthi.svg'; // Import your logo
+
+const ComplainBox = () => {
+ const [name, setName] = useState('');
+ const [phoneNumber, setPhoneNumber] = useState('');
+ const [email, setEmail] = useState('');
+ const [complain, setComplain] = useState('');
+ const [alert, setAlert] = useState(null); // To show success or error messages
+
+ const handleComplain = async (e) => {
+ e.preventDefault();
+
+ const complaintData = { name, phoneNumber, email, complain };
+
+ try {
+ const response = await axios.post('http://localhost:3000/api/complaint', complaintData);
+
+ // Reset the form fields after successful submission
+ setName('');
+ setPhoneNumber('');
+ setEmail('');
+ setComplain('');
+
+ // Set success alert message
+ setAlert({ type: 'success', message: response.data.message || 'Complaint submitted successfully!' });
+
+ } catch (error) {
+ // Handle error in a user-friendly way
+ setAlert({
+ type: 'error',
+ message: error.response ? error.response.data.message : 'Error submitting complaint. Please try again.',
+ });
+ }
+ };
+
+ return (
+
+ );
+};
+
+export default ComplainBox;
diff --git a/frontend/src/Pages/ContactUs.jsx b/frontend/src/Pages/ContactUs.jsx
index a7511e8..6477ea1 100644
--- a/frontend/src/Pages/ContactUs.jsx
+++ b/frontend/src/Pages/ContactUs.jsx
@@ -1,353 +1,513 @@
// src/components/ContactUs.jsx
-import React, { useEffect } from 'react';
+import React, { useEffect, useState } from "react";
import {
- FaPhone,
- FaEnvelope,
- FaMapMarkerAlt,
- FaTwitter,
- FaFacebook,
-} from 'react-icons/fa';
-import { AiOutlineArrowUp,AiOutlineArrowDown } from 'react-icons/ai';
+ FaPhone,
+ FaEnvelope,
+ FaMapMarkerAlt,
+ FaTwitter,
+ FaFacebook,
+} from "react-icons/fa";
+import { AiOutlineArrowUp, AiOutlineArrowDown } from "react-icons/ai";
const ContactUs = () => {
- // Function to scroll to the top of the page
- const scrollToTop = () => {
- window.scrollTo({
- top: 0,
- behavior: 'smooth',
- });
- };
- const scrollToBottom = () => {
- window.scrollTo({
- top: 10000,
- behavior: 'smooth',
- });
- };
- useEffect(() => {
- document.title = 'Station Saarthi |ContactUs';
- }, []);
+ // Function to scroll to the top of the page
+ const scrollToTop = () => {
+ window.scrollTo({
+ top: 0,
+ behavior: "smooth",
+ });
+ };
+ const scrollToBottom = () => {
+ window.scrollTo({
+ top: 10000,
+ behavior: "smooth",
+ });
+ };
+ useEffect(() => {
+ document.title = "Station Saarthi |ContactUs";
+ }, []);
- return (
-
- {/* Header Section */}
-
-
Contact Us
-
Indian Railways
-
+ const [formData, setFormData] = useState({
+ senderEmail: "",
+ subject: "",
+ message: "",
+ });
- {/* General Information */}
-
-
-
-
General Information
-
-
-
-
-
-
- Phone Number: 139 (Railway Enquiry)
-
-
-
-
-
- Email: customercare@indianrailways.gov.in
-
-
-
-
-
+ const [isLoading, setIsLoading] = useState(false);
+ const [alert, setAlert] = useState(false);
+ const API_URL = "http://localhost:3000";
- {/* Emergency Services */}
-
-
-
-
Emergency Services
-
-
-
-
-
-
- Phone Number: 182 (Security & Emergencies)
-
-
-
-
-
- Phone Number: 138 (Passenger Helpline)
-
-
-
-
-
- Email: emergencyservices@indianrailways.gov.in
-
-
-
-
-
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData((prevData) => ({
+ ...prevData,
+ [name]: value,
+ }));
+ };
- {/* Reservation and Ticketing */}
-
-
-
-
Reservation and Ticketing
-
-
-
-
-
-
- Phone Number: 139 (IRCTC Helpline)
-
-
-
-
-
- Email: care@irctc.co.in
-
-
-
- Website: {' '}
-
- IRCTC Website
-
-
-
-
-
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setIsLoading(true);
+
+ try {
+ const response = await fetch(`${API_URL}/contact/contactus`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ mail: formData.senderEmail,
+ subject: formData.subject,
+ message: formData.message,
+ }),
+ });
+
+ if (response.ok) {
+ setTimeout(() => {
+ setIsLoading(false);
+ setAlert(true);
+ setFormData({
+ senderEmail: "",
+ subject: "",
+ message: "",
+ });
+ }, 2000);
+
+ setTimeout(() => {
+ setAlert(false);
+ }, 4000);
+ } else {
+ alert("Something went wrong, please try later!!");
+ setIsLoading(false);
+ }
+ } catch (err) {
+ console.error("Mail sending failed: ", err);
+ alert("Something went wrong, please try later!!");
+ setIsLoading(false);
+ }
+ };
- {/* Lost & Found */}
-
-
-
-
Lost & Found
-
-
-
-
-
- Phone Number: 139
-
-
-
-
- Email: lostandfound@indianrailways.gov.in
-
-
-
-
-
+ return (
+
+ {/* Header Section */}
+
+
Contact Us
+
Indian Railways
+
- {/* Grievances and Complaints */}
-
-
-
-
Grievances and Complaints
-
-
-
-
-
-
- Phone Number: 139 (Complaint Registration)
-
-
-
-
-
- Email: complaints@indianrailways.gov.in
-
-
-
- Online Portal: {' '}
-
- RailMadad
-
-
-
-
-
+ {/* E-Mail Section */}
+
- {/* Railway Police Force (RPF) */}
-
-
-
-
Railway Police Force (RPF)
-
-
-
-
-
- Phone Number: 182
-
-
-
-
- Email: rpf@indianrailways.gov.in
-
-
-
-
-
+ {/* General Information */}
+
+
+
+
+ General Information
+
+
+
+
+
+
+
+ Phone Number: 139 (Railway Enquiry)
+
+
+
+
+
+ Email: customercare@indianrailways.gov.in
+
+
+
+
+
- {/* Corporate Office */}
-
-
-
-
Corporate Office
-
-
-
-
-
-
- Address: Indian Railways Corporate Office, New Delhi, India
-
-
-
-
-
- Phone Number: +91-11-23389184
-
-
-
-
-
- Email: corporateaffairs@indianrailways.gov.in
-
-
-
-
-
+ {/* Emergency Services */}
+
+
+
+
+ Emergency Services
+
+
+
+
+
+
+
+ Phone Number: 182 (Security & Emergencies)
+
+
+
+
+
+ Phone Number: 138 (Passenger Helpline)
+
+
+
+
+
+ Email: emergencyservices@indianrailways.gov.in
+
+
+
+
+
- {/* Stay Connected */}
-
-
-
-
Stay Connected
-
-
-
+ {/* Reservation and Ticketing */}
+
+
+
+
+ Reservation and Ticketing
+
+
+
+
+
+
+
+ Phone Number: 139 (IRCTC Helpline)
+
+
+
+
+
+ Email: care@irctc.co.in
+
+
+
+ Website: {" "}
+
+ IRCTC Website
+
+
+
+
+
- {/* Feedback */}
-
+ {/* Lost & Found */}
+
+
+
+
Lost & Found
+
+
+
+
+
+
+ Phone Number: 139
+
+
+
+
+
+ Email: lostandfound@indianrailways.gov.in
+
+
+
+
+
- {/* Back to Top Button */}
-
-
-
-
-
-
+ {/* Grievances and Complaints */}
+
+
+
+
+ Grievances and Complaints
+
+
+
+
+
+
+
+ Phone Number: 139 (Complaint Registration)
+
+
+
+
+
+ Email: complaints@indianrailways.gov.in
+
+
+
+ Online Portal: {" "}
+
+ RailMadad
+
+
+
+
+
+
+ {/* Divisional Railway Manager (DRM) Offices */}
+
+
+
+
+ Divisional Railway Manager (DRM) Offices
+
+
+
+
+
+
+
+ Northern Railway DRM Office:{" "}
+ drm.nr@indianrailways.gov.in
+
+
+
+
+
+ Western Railway DRM Office:{" "}
+ drm.wr@indianrailways.gov.in
+
+
+
+
+
+ Southern Railway DRM Office:{" "}
+ drm.sr@indianrailways.gov.in
+
+
+
+
+
+ Eastern Railway DRM Office:{" "}
+ drm.er@indianrailways.gov.in
+
+
+
+
+
+
+ {/* Railway Police Force (RPF) */}
+
+
+
+
+ Railway Police Force (RPF)
+
+
+
+
+
+
+
+ Phone Number: 182
+
+
+
+
+
+ Email: rpf@indianrailways.gov.in
+
+
+
+
+
+
+ {/* Corporate Office */}
+
+
+
+
+ Corporate Office
+
+
+
+
+
+
+
+ Address: Indian Railways Corporate Office, New Delhi, India
+
+
+
+
+
+ Phone Number: +91-11-23389184
+
+
+
+
+
+ Email: corporateaffairs@indianrailways.gov.in
+
+
+
- );
+
+
+ {/* Stay Connected */}
+
+
+
+
+ Stay Connected
+
+
+
+
+
+ {/* Feedback */}
+
+
+ {/* Back to Top Button */}
+
+
+
+
+
+
+
+ );
};
export default ContactUs;
diff --git a/frontend/src/Pages/Faq.css b/frontend/src/Pages/Faq.css
new file mode 100644
index 0000000..468712b
--- /dev/null
+++ b/frontend/src/Pages/Faq.css
@@ -0,0 +1,77 @@
+.faq-section {
+ background-color: #F3F4F6;
+ padding: 2rem;
+ }
+
+ /* Heading styling */
+ .faq-main-heading {
+ font-size: 2.5rem;
+ color: #1a73e8;
+ text-align: center;
+ margin-bottom: 2rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ }
+
+ /* Container styling */
+ .faq-container {
+ max-width: 800px;
+ margin: 0 auto;
+ }
+
+ /* FAQ item styling */
+ .faq-item {
+ background-color: white;
+ margin: 1.5rem 0;
+ padding: 1.5rem;
+ border-radius: 10px;
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
+ transition: transform 0.3s ease;
+ cursor: pointer;
+ }
+
+ .faq-item:hover {
+ transform: translateY(-5px);
+ }
+
+ .faq-question {
+ font-size: 1.5rem;
+ color: #1a73e8; /* Blue */
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-weight: 600;
+ }
+
+ .faq-answer {
+ font-size: 1.1rem;
+ color: black;
+ margin-top: 1rem;
+ line-height: 1.6;
+ padding-left: 1rem;
+ border-left: 3px solid #1a73e8; /* Accent line for visual appeal */
+ animation: fadeIn 0.3s ease-in-out;
+ }
+
+ @keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ /* Icon styling */
+ .faq-icon {
+ font-size: 1.4rem;
+ color: #1a73e8;
+ transition: transform 0.3s ease;
+ }
+
+ .rotate {
+ transform: rotate(180deg);
+ }
+
diff --git a/frontend/src/Pages/Faq.jsx b/frontend/src/Pages/Faq.jsx
new file mode 100644
index 0000000..5133de1
--- /dev/null
+++ b/frontend/src/Pages/Faq.jsx
@@ -0,0 +1,80 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import backicon from '../assets/svg/backicon.svg';
+import './Faq.css';
+
+const Faq = () => {
+ const navigate = useNavigate(); // Initialize the useNavigate hook
+ const [activeIndex, setActiveIndex] = useState(null);
+
+ const faqData = [
+ {
+ question: "How can I book a station guide service?",
+ answer: "To book a station guide service, navigate to the 'Booking' page, select the service you need, and follow the steps to confirm your booking.",
+ },
+ {
+ question: "What payment methods are accepted?",
+ answer: "We accept various payment methods, including credit/debit cards, UPI, and popular digital wallets.",
+ },
+ {
+ question: "How can I cancel or modify my booking?",
+ answer: "You can cancel or modify your booking from your account under 'My Bookings'. Select the booking and choose the desired option.",
+ },
+ {
+ question: "Is there a way to contact support?",
+ answer: "Yes, you can contact our support team via the 'Help and Support' page, where we offer chat and email options for assistance.",
+ },
+ {
+ question: "Are there any discounts available?",
+ answer: "Check our 'Offers' section regularly for seasonal discounts and promotional codes.",
+ },
+ {
+ question: "What are the operating hours of the station guide service?",
+ answer: "Our station guide service operates 24/7 to assist you at any time.",
+ },
+ {
+ question: "Can I provide feedback about the service?",
+ answer: "Absolutely! We welcome feedback through the 'Feedback' section on our website.",
+ },
+ {
+ question: "What should I do if I lose my booking confirmation?",
+ answer: "If you lose your booking confirmation, you can retrieve it from your account or contact customer support for assistance.",
+ },
+ ];
+
+ const toggleAnswer = (index) => {
+ setActiveIndex(activeIndex === index ? null : index);
+ };
+
+ const HomeClick = () => {
+ navigate('/'); // Navigates to the home page
+ };
+
+ return (
+
+
+
+
+
Frequently Asked Questions
+
+ {faqData.map((item, index) => (
+
toggleAnswer(index)}>
+
+ {item.question}
+
+ βΌ
+
+
+ {activeIndex === index && (
+
+ {item.answer}
+
+ )}
+
+ ))}
+
+
+ );
+};
+
+export default Faq;
diff --git a/frontend/src/Pages/Firebase.jsx b/frontend/src/Pages/Firebase.jsx
new file mode 100644
index 0000000..fd25afc
--- /dev/null
+++ b/frontend/src/Pages/Firebase.jsx
@@ -0,0 +1,24 @@
+import { initializeApp } from "firebase/app";
+import { getAuth, GoogleAuthProvider, signInWithPopup } from "firebase/auth"; // Import GoogleAuthProvider and signInWithPopup
+
+// Firebase configuration
+const firebaseConfig = {
+ apiKey: "AIzaSyCZjGQb8lWxKdPf94ipmk-xleQbuSAe-xU",
+ authDomain: "scrollme-40ba6.firebaseapp.com",
+ projectId: "scrollme-40ba6",
+ storageBucket: "scrollme-40ba6.appspot.com",
+ messagingSenderId: "748771881750",
+ appId: "1:748771881750:web:2cb97bb2c7b7468a7c1637"
+};
+
+// Initialize Firebase
+const app = initializeApp(firebaseConfig);
+
+// Initialize Firebase Authentication and get a reference to the auth service
+const auth = getAuth(app);
+
+// Set up Google Auth Provider
+const provider = new GoogleAuthProvider();
+
+// Export app, auth, provider, and signInWithPopup
+export { app, auth, provider, signInWithPopup };
diff --git a/frontend/src/Pages/GoogleTranslate.jsx b/frontend/src/Pages/GoogleTranslate.jsx
new file mode 100644
index 0000000..b5df449
--- /dev/null
+++ b/frontend/src/Pages/GoogleTranslate.jsx
@@ -0,0 +1,148 @@
+import React, { useEffect } from "react";
+
+const GoogleTranslate = () => {
+ useEffect(() => {
+ window.googleTranslateInit = () => {
+ if (!window.google?.translate?.TranslateElement) {
+ setTimeout(window.googleTranslateInit, 100);
+ } else {
+ new window.google.translate.TranslateElement(
+ {
+ pageLanguage: "en",
+ includedLanguages:
+ "en,hi,pa,sa,mr,ur,bn,es,ja,ko,zh-CN,es,nl,fr,de,it,ta,te",
+ layout:
+ window.google.translate.TranslateElement.InlineLayout.HORIZONTAL,
+ defaultLanguage: "en",
+ autoDisplay: false,
+ },
+ "google_element"
+ );
+ }
+ cleanUpGadgetText();
+ };
+
+ const loadGoogleTranslateScript = () => {
+ if (!document.getElementById("google_translate_script")) {
+ const script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src =
+ "https://translate.google.com/translate_a/element.js?cb=googleTranslateInit";
+ script.id = "google_translate_script";
+ script.onerror = () =>
+ console.error("Error loading Google Translate script");
+ document.body.appendChild(script);
+ }
+ };
+
+ const cleanUpGadgetText = () => {
+ const gadgetElement = document.querySelector(".goog-te-gadget");
+ if (gadgetElement) {
+ const textNodes = gadgetElement.childNodes;
+ textNodes.forEach((node) => {
+ if (node.nodeType === Node.TEXT_NODE) {
+ node.textContent = ""; // Clear text content
+ }
+ });
+ }
+ };
+ loadGoogleTranslateScript();
+
+ if (window.google && window.google.translate) {
+ window.googleTranslateInit();
+ }
+
+ return () => {
+ // Cleanup logic if necessary
+ };
+ }, []);
+
+ return (
+
+
+
+ );
+};
+
+export default GoogleTranslate;
diff --git a/frontend/src/Pages/Herosection.jsx b/frontend/src/Pages/Herosection.jsx
index 4108dd5..ce4edac 100644
--- a/frontend/src/Pages/Herosection.jsx
+++ b/frontend/src/Pages/Herosection.jsx
@@ -1,134 +1,251 @@
-import React from 'react';
-import './Herosection.css';
-import logo from '../assets/stationsaarthi.svg';
-import navigationsvg from '../assets/svg/navigation.svg';
-import bookingsvg from '../assets/svg/bookings.svg';
-import stationsvg from '../assets/svg/station.svg';
-import noticationsvg from '../assets/svg/notification.svg';
-import mapsvg from '../assets/svg/3dmap.svg';
-import schedulesvg from '../assets/svg/schedule.svg';
-import searchsvg from '../assets/svg/search.svg';
-import { useNavigate } from 'react-router-dom';
-import HamburgerMenu from './hamburger';
-import contributorsvg from '../assets/svg/contributor.svg';
-import chatbotsvg from '../assets/svg/chatbot.svg';
-import Chatbot from '../components/chatbot';
-import Navbar from '../components/navbar';
-import Language from '../components/language';
+import React from "react";
+import "./Herosection.css";
+import ThemeToggle from "../components/ThemeToggle"
+import logo from "../assets/stationsaarthi.svg";
+import navigationsvg from "../assets/svg/navigation.svg";
+import bookingsvg from "../assets/svg/bookings.svg";
+import stationsvg from "../assets/svg/station.svg";
+import noticationsvg from "../assets/svg/notification.svg";
+import mapsvg from "../assets/svg/3dmap.svg";
+import schedulesvg from "../assets/svg/schedule.svg";
+import searchsvg from "../assets/svg/search.svg";
+import { useNavigate } from "react-router-dom";
+import HamburgerMenu from "./hamburger";
+import contributorsvg from "../assets/svg/contributor.svg";
+import chatbotsvg from "../assets/svg/chatbot.svg";
+import Chatbot from "../components/chatbot";
+import Navbar from "../components/navbar";
+import Language from "../components/language";
import { FaUserAlt } from "react-icons/fa";
-import Popup from '../components/popup';
+import Popup from "../components/popup";
+import GoogleTranslate from "./GoogleTranslate";
const Herosection = () => {
- const navigate = useNavigate();
+ const navigate = useNavigate();
- const LoginClick = () => {
- navigate('/Login'); // Navigates to the login page
- };
- const RegisterClick = () => {
- navigate('/Register'); // Navigates to the login page
- };
- const StationCLick = () => {
- navigate('/Stations'); // Navigates to the login page
- };
- const UserCLick = () => {
- navigate('/user'); // Navigates to the login page
- }
- const NavigationCLick = () => {
- navigate('/Navigation'); // Navigates to the login page
- };
- const BookingCLick = () => {
- navigate('/Booking'); // Navigates to the login page
- };
- const MapCLick = () => {
- navigate('/3DMap'); // Navigates to the login page
- }
- const ScheduleCLick = () => {
- navigate('/Schedule'); // Navigates to the login page
- }
- const NotificationCLick = () => {
- navigate('/Notification'); // Navigates to the login page
- }
- const ContributorCLick = () => {
- navigate('/contributor'); // Navigates to the login page
- }
-
+ const LoginClick = () => {
+ navigate("/Login"); // Navigates to the login page
+ };
+ const RegisterClick = () => {
+ navigate("/Register"); // Navigates to the login page
+ };
+ const StationCLick = () => {
+ navigate("/Stations"); // Navigates to the login page
+ };
+ const UserCLick = () => {
+ navigate("/user"); // Navigates to the login page
+ };
+ const NavigationCLick = () => {
+ navigate("/Navigation"); // Navigates to the login page
+ };
+ const BookingCLick = () => {
+ navigate("/Booking"); // Navigates to the login page
+ };
+ const MapCLick = () => {
+ navigate("/3DMap"); // Navigates to the login page
+ };
+ const ScheduleCLick = () => {
+ navigate("/Schedule"); // Navigates to the login page
+ };
+ const NotificationCLick = () => {
+ navigate("/Notification"); // Navigates to the login page
+ };
+ const ContributorCLick = () => {
+ navigate("/contributor"); // Navigates to the login page
+ };
+ const ContactClick = () => {
+ navigate("/contactus");
+ };
- return (
- <>
+ return (
+ <>
+
+
+
+
+
-
-
-
Namaste !! Yatree
-
+
+
+
+
-
-
-
Station Saarthi : Your Platform Guide
-
- {/*
-
*/}
-
-
-
+
+
+
+
+
+
+
+
-
-
-
+ Namaste !! Yatree{" "}
+
+
+
+
+
+ Station Saarthi : Your Platform Guide
+
+
+ {/*
+
*/}
+
+
+
+
+
+
-
Contributors
-
+ "
+ />
+
Contact Us
+
+
+
+
Contributors
+
+
+
+
+
+ Navigation
+
+
+
+
+
+ Booking
+
+
+
+
+
+ Station
+
+
+
+
{" "}
+
+ {" "}
+ 3D Map
+
+
-
-
-
- Navigation
-
-
-
-
-
- Booking
-
-
-
-
-
- Station
-
-
-
3D Map
-
-
Schedule
-
-
Notification
+
+
+
+ {" "}
+ Schedule
+
+
-
-
- >
- );
+
+
{" "}
+
+ {" "}
+ Notification
+
+
+
+
+ >
+ );
};
-export default Herosection;
\ No newline at end of file
+export default Herosection;
diff --git a/frontend/src/Pages/LoginPage.jsx b/frontend/src/Pages/LoginPage.jsx
index 06790ca..cc5b09d 100644
--- a/frontend/src/Pages/LoginPage.jsx
+++ b/frontend/src/Pages/LoginPage.jsx
@@ -1,32 +1,35 @@
-import React, { useState, useEffect } from "react";
+import { useState, useEffect } from "react";
import logo from "../assets/stationsaarthi.svg"; // Import your logo
import { useNavigate } from "react-router-dom";
import backicon from "../assets/svg/backicon.svg"; // Assuming you have a back icon
import { loginValidation } from "../validations/validation";
import { MdOutlinePassword } from "react-icons/md";
import { FaUser } from "react-icons/fa";
+import { auth, provider, signInWithPopup } from "./Firebase"; // Import Firebase authentication methods
+import { FaGoogle } from "react-icons/fa"; // Import Google icon
const Login = () => {
useEffect(() => {
document.title = "Station Saarthi | LoginPage";
}, []);
+
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
- const [loginSuccess, setLoginSuccess] = useState(false); // State for login success message
+ const [loginSuccess, setLoginSuccess] = useState(false);
const [errors, setErrors] = useState({});
- const [passwordVisible, setPasswordVisible] = useState(false); // State for password visibility
+ const [passwordVisible, setPasswordVisible] = useState(false);
const navigate = useNavigate();
const togglePasswordVisibility = () => {
- setPasswordVisible(!passwordVisible); // Toggle password visibility
+ setPasswordVisible(!passwordVisible);
};
const RegisterClick = () => {
- navigate("/Register"); // Navigates to the login page
+ navigate("/Register");
};
const HomeClick = () => {
- navigate("/"); // Navigates to the home page
+ navigate("/");
};
const handleLogin = async (e) => {
@@ -42,16 +45,14 @@ const Login = () => {
const newErrors = {};
error.inner.forEach((err) => {
newErrors[err.path] = err.message;
- // newErrors[err.path] = err.errors[0];
});
-
setErrors(newErrors);
return;
}
// Handle login logic here
- setLoginSuccess(true); // Set login success to true upon successful login
- setUsername(""); // Clear input fields after login
+ setLoginSuccess(true);
+ setUsername("");
setPassword("");
};
@@ -59,22 +60,32 @@ const Login = () => {
navigate("/password-recovery");
};
+ const handleGoogleLogin = async () => {
+ try {
+ const result = await signInWithPopup(auth, provider);
+ const user = result.user;
+ console.log("Google User Info:", user);
+ // Optionally navigate or handle user state here
+ } catch (error) {
+ console.error("Google login error:", error);
+ }
+ };
+
return (
-
- {/* Logo and Title */}
-
-
+
+
+
-
+
-
+
Station Saarthi
-
+
Your Trusted Platform Guide
@@ -83,104 +94,116 @@ const Login = () => {
- {/* Login Heading */}
-
+
Login
- {/* Success Message */}
{loginSuccess && (
-
+
Login successful! Welcome back.
)}
{/* Username Input */}
-
+
Username
setUsername(e.target.value)}
- placeholder='Enter your username'
- className='w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500'
+ placeholder="Enter your username"
+ className="w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
{errors.username && (
-
{errors.username}
+
{errors.username}
)}
{/* Password Input */}
-
-
- Password
+
+
+ Password
setPassword(e.target.value)}
- placeholder='Enter your password'
- className='w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500'
+ placeholder="Enter your password"
+ className="w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
required
- />{" "}
+ />
{passwordVisible ? (
- visibility_off // Closed eye icon
+ visibility_off
) : (
- visibility // Open eye icon
+ visibility
)}
{errors.password && (
-
{errors.password}
+
{errors.password}
)}
+
+ {/* Adjusted Forgot Password Link */}
+
+
+ Forgot Password?
+
+
+
{/* Login Button */}
Login
-
- {/* Forgot Password Link */}
-
+ {/* Google Login Button */}
- Forgot Password?
+
+ Sign in with Google
-
+ {/* Don't have an account link */}
+
+
+ Don't have an account?{" "}
+
+ Register
+
+
+
- {/* Don't have an account link */}
-
- Don't have an account?{" "}
-
- Register
-
-
+
);
};
diff --git a/frontend/src/Pages/PasswordRecovery.jsx b/frontend/src/Pages/PasswordRecovery.jsx
index 8a7e1fc..beb1dae 100644
--- a/frontend/src/Pages/PasswordRecovery.jsx
+++ b/frontend/src/Pages/PasswordRecovery.jsx
@@ -3,15 +3,114 @@ import { useNavigate } from "react-router-dom";
const PasswordRecovery = () => {
const [email, setEmail] = useState("");
+ const [otp, setOtp] = useState(""); // For OTP input
+ const [newPassword, setNewPassword] = useState(""); // For new password input
+ const [confirmPassword, setConfirmPassword] = useState(""); // For confirm password input
+ const [step, setStep] = useState(1); // For handling the steps (1: Email, 2: OTP, 3: Password Reset)
+ const [otpDisabled, setOtpDisabled] = useState(false); // For disabling OTP input after submission
const [message, setMessage] = useState("");
+ const [error, setError] = useState("");
+ const [loading, setLoading] = useState(false);
const navigate = useNavigate();
+ // Step 1: Handle sending OTP to email
const handlePasswordRecovery = async (e) => {
e.preventDefault();
- // Implement password recovery logic here
- setMessage(
- "If an account with that email exists, a password recovery link has been sent."
- );
+ setMessage("");
+ setError("");
+ setLoading(true);
+
+ try {
+ const response = await fetch("http://localhost:5000/station/send-otp", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ email }),
+ });
+
+ const data = await response.json();
+
+ if (response.ok) {
+ setMessage("OTP has been sent to your email.");
+ setStep(2); // Move to OTP input step
+ } else {
+ setError(data.error || "Failed to send OTP. Please try again.");
+ }
+ } catch (error) {
+ setError("An error occurred. Please try again later.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Step 2: Handle OTP verification
+ const handleVerifyOTP = async (e) => {
+ e.preventDefault();
+ setMessage("");
+ setError("");
+ setLoading(true);
+
+ try {
+ const response = await fetch("http://localhost:5000/station/verify-otp", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ email, otp }),
+ });
+
+ const data = await response.json();
+
+ if (response.ok) {
+ setMessage("OTP verified successfully. You can now reset your password.");
+ setStep(3); // Move to password reset step
+ setOtpDisabled(true); // Disable OTP input after successful verification
+ } else {
+ setError(data.error || "Invalid OTP. Please try again.");
+ }
+ } catch (error) {
+ setError("An error occurred. Please try again later.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Step 3: Handle new password submission
+ const handlePasswordReset = async (e) => {
+ e.preventDefault();
+ setMessage("");
+ setError("");
+ setLoading(true);
+
+ if (newPassword !== confirmPassword) {
+ setError("Passwords do not match.");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ const response = await fetch("http://localhost:5000/station/reset-password", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ email, newPassword }),
+ });
+
+ const data = await response.json();
+
+ if (response.ok) {
+ setMessage("Password reset successfully. You can now log in.");
+ navigate("/login");
+ } else {
+ setError(data.error || "Failed to reset password. Please try again.");
+ }
+ } catch (error) {
+ setError("An error occurred. Please try again later.");
+ } finally {
+ setLoading(false);
+ }
};
const handleBackToLogin = () => {
@@ -19,44 +118,123 @@ const PasswordRecovery = () => {
};
return (
-
-
-
+
+
+
Password Recovery
+
+ {/* Success Message */}
{message && (
-
+
{message}
)}
-
-
-
+
+ {/* Error Message */}
+ {error && (
+
+ {error}
+
+ )}
+
+ {/* Form */}
+
+ {/* Email Field (always visible) */}
+
+
Email
setEmail(e.target.value)}
- placeholder='Enter your email'
- className='w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500'
+ placeholder="Enter your email"
+ className="w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
required
+ disabled={step !== 1} // Disable email field after step 1
/>
+
+ {/* OTP Field (visible after step 1) */}
+ {step >= 2 && (
+
+
+ OTP
+
+ setOtp(e.target.value)}
+ placeholder="Enter the OTP"
+ className="w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+ required
+ disabled={otpDisabled} // Disable OTP input after step 2
+ />
+
+ )}
+
+ {/* Password Fields (visible after step 2) */}
+ {step === 3 && (
+ <>
+
+
+ New Password
+
+ setNewPassword(e.target.value)}
+ placeholder="Enter new password"
+ className="w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+ required
+ />
+
+
+
+
+ Confirm Password
+
+ setConfirmPassword(e.target.value)}
+ placeholder="Confirm new password"
+ className="w-full px-4 py-2 transition duration-300 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+ required
+ />
+
+ >
+ )}
+
- Recover Password
+ {loading
+ ? step === 3
+ ? "Resetting Password..."
+ : step === 2
+ ? "Verifying..."
+ : "Sending..."
+ : step === 3
+ ? "Reset Password"
+ : step === 2
+ ? "Verify OTP"
+ : "Recover Password"}
+
Back to Login
diff --git a/frontend/src/Pages/Payment.jsx b/frontend/src/Pages/Payment.jsx
index 709ce12..851ddee 100644
--- a/frontend/src/Pages/Payment.jsx
+++ b/frontend/src/Pages/Payment.jsx
@@ -1,34 +1,188 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
+import Swal from 'sweetalert2';
import backicon from '../assets/svg/backicon.svg';
-
-
const Payment = () => {
+ const [name, setName] = useState('');
+ const [phoneNumber, setPhoneNumber] = useState('');
+ const [nationality, setNationality] = useState('91');
+ const [email, setEmail] = useState('');
+ const [address, setAddress] = useState('');
const [paymentMethod, setPaymentMethod] = useState('');
const [cardNumber, setCardNumber] = useState('');
const [expiryDate, setExpiryDate] = useState('');
const [cvv, setCvv] = useState('');
+ const [upiId, setUpiId] = useState('');
+ const [errors, setErrors] = useState({});
+
+ const navigate = useNavigate();
+
+ const validateForm = () => {
+ let formErrors = {};
+ if (!name.trim()) formErrors.name = 'Name is required';
+ if (!/^[A-Za-z\s]+$/.test(name)) formErrors.name = 'Name must contain only letters and spaces';
+
+ if (!phoneNumber.trim()) formErrors.phoneNumber = 'Phone number is required';
+ if (!/^\d{10}$/.test(phoneNumber)) formErrors.phoneNumber = 'Phone number must be 10 digits';
+
+ if (!email.trim()) formErrors.email = 'Email is required';
+ if (!/^[\w.%+-]+@[a-zA-Z\d.-]+\.[a-zA-Z]{2,}$/.test(email)) formErrors.email = 'Invalid email format';
+
+ if (!address.trim()) formErrors.address = 'Address is required';
+
+ if ((paymentMethod === 'credit_card' || paymentMethod === 'debit_card') && !/^\d{4}-\d{4}-\d{4}-\d{4}$/.test(cardNumber)) {
+ formErrors.cardNumber = 'Card number must be in the format 1234-5678-9012-3456';
+ }
+
+ if ((paymentMethod === 'credit_card' || paymentMethod === 'debit_card') && !/^(0[1-9]|1[0-2])\/\d{2}$/.test(expiryDate)) {
+ formErrors.expiryDate = 'Expiry date must be in MM/YY format';
+ }
+
+ if ((paymentMethod === 'credit_card' || paymentMethod === 'debit_card') && !/^\d{3,4}$/.test(cvv)) {
+ formErrors.cvv = 'CVV must be 4 digits';
+ }
+
+ if (paymentMethod === 'upi' && !/^[\w.-]+@[a-zA-Z]{3,}$/.test(upiId)) {
+ formErrors.upiId = 'Invalid UPI ID format';
+ }
+
+ setErrors(formErrors);
+ return Object.keys(formErrors).length === 0;
+ };
+
+ const formatCardNumber = (value) => {
+ return value.replace(/\D/g, '').replace(/(\d{4})(?=\d)/g, '$1-').slice(0, 19);
+ };
+
+ const formatExpiryDate = (value) => {
+ return value.replace(/\D/g, '').replace(/(\d{2})(\d)/, '$1/$2').slice(0, 5);
+ };
const handleSubmit = (e) => {
e.preventDefault();
- console.log('Payment submitted:', { paymentMethod, cardNumber, expiryDate, cvv });
+ if (validateForm()) {
+ Swal.fire({
+ title: 'Success!',
+ text: 'Payment submitted successfully!',
+ icon: 'success',
+ confirmButtonText: 'OK'
+ }).then(() => {
+ navigate('/');
+ });
+ }
};
- const navigate = useNavigate();
+ const HomeClick = () => {
+ navigate('/'); // Navigates to the home page
+ };
- const HomeClick = () => {
- navigate('/'); // Navigates to the home page
- };
return (
-
-
-
-
+
+
+
Payment Page
+
+
+ Full Name
+
+
setName(e.target.value)}
+ placeholder="Enter your full name"
+ required
+ />
+ {errors.name &&
{errors.name}
}
+
+
+ {/* Nationality and Phone Number Row */}
+
+
+
+ Nationality
+
+ setNationality(e.target.value)}
+ required
+ >
+ India (+91)
+ USA (+1)
+ UK (+44)
+ Australia (+61)
+ Japan (+81)
+ Germany (+49)
+ France (+33)
+ Italy (+39)
+ Switzerland (+41)
+ China (+86)
+ Brazil (+55)
+ Russia (+7)
+ Sweden (+46)
+ Singapore (+65)
+ Singapore (+65)
+ Spain (+34)
+ Indonesia (+62)
+ Thailand (+66)
+ Philippines (+63)
+ South Africa (+27)
+ Malaysia (+60)
+ Portugal (+351)
+ Greece (+30)
+
+
+
+
+
+ Phone Number
+
+
setPhoneNumber(e.target.value)}
+ placeholder="Enter your 10-digit phone number"
+ required
+ />
+ {errors.phoneNumber &&
{errors.phoneNumber}
}
+
+
+
+
+
+ Email Address
+
+
setEmail(e.target.value)}
+ placeholder="Enter your email address"
+ required
+ />
+ {errors.email &&
{errors.email}
}
+
+
+
+
+ Address
+
+
setAddress(e.target.value)}
+ placeholder="Enter your address"
+ required
+ >
+ {errors.address &&
{errors.address}
}
+
+
Select Payment Method
@@ -42,75 +196,87 @@ const Payment = () => {
Choose a payment method
Credit Card
Debit Card
- Apple Pay
- Google Pay
+ UPI (Google Pay/Other UPI)
+
-
- {paymentMethod === 'credit_card' || paymentMethod === 'debit_card' ? (
- <>
-
-
- Card Number
-
- setCardNumber(e.target.value)}
- required
- />
-
-
-
- >
- ) : null}
-
- {paymentMethod === 'apple_pay' || paymentMethod === 'google_pay' ? (
-
-
- UPI ID
-
-
+
+ {paymentMethod && (
+
+ {paymentMethod === 'credit_card' || paymentMethod === 'debit_card' ? (
+ <>
+
+
+ Card Number
+
+
setCardNumber(formatCardNumber(e.target.value))}
+ placeholder="1234-5678-9012-3456"
+ required
+ />
+ {errors.cardNumber &&
{errors.cardNumber}
}
+
+
+
+
+
+ Expiry Date
+
+
setExpiryDate(formatExpiryDate(e.target.value))}
+ placeholder="MM/YY"
+ required
+ />
+ {errors.expiryDate &&
{errors.expiryDate}
}
+
+
+
+ CVV
+
+
setCvv(e.target.value)}
+ placeholder="1234"
+ required
+ />
+ {errors.cvv &&
{errors.cvv}
}
+
+
+ >
+ ) : paymentMethod === 'upi' || paymentMethod === 'google_pay' ? (
+ <>
+
+
+ UPI ID
+
+
setUpiId(e.target.value)}
+ placeholder="example@upi"
+ required
+ />
+ {errors.upiId &&
{errors.upiId}
}
+
+ >
+ ) : null}
- ) : null}
-
+ )}
+
- Pay Now
+ Submit Payment
@@ -118,4 +284,4 @@ const Payment = () => {
);
};
-export default Payment;
\ No newline at end of file
+export default Payment;
diff --git a/frontend/src/Pages/PrivacyPolicy.css b/frontend/src/Pages/PrivacyPolicy.css
new file mode 100644
index 0000000..db5fdbe
--- /dev/null
+++ b/frontend/src/Pages/PrivacyPolicy.css
@@ -0,0 +1,57 @@
+.privacy-policy-container {
+ max-width: 800px;
+ margin: 20px auto;
+ padding: 40px 20px;
+ background-color: #f5f5f5;
+ border-radius: 10px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ color: #333;
+ font-family: Arial, sans-serif;
+}
+
+.privacy-policy-header {
+ text-align: center;
+ margin-bottom: 40px;
+}
+
+.privacy-policy-header h1 {
+ font-size: 2.2rem;
+ color: #0066cc;
+ margin-bottom: 10px;
+}
+
+.privacy-policy-header p {
+ font-size: 1.1rem;
+ color: #444;
+}
+
+.privacy-policy-section h2 {
+ font-size: 1.6rem;
+ color: #333;
+ margin-bottom: 16px;
+ border-bottom: 2px solid #0066cc;
+ padding-bottom: 6px;
+}
+
+.privacy-policy-section p {
+ font-size: 1rem;
+ line-height: 1.6;
+ color: #555;
+ margin-bottom: 18px;
+}
+
+.privacy-policy-section ul {
+ margin-left: 20px;
+ margin-bottom: 18px;
+}
+
+.privacy-policy-section ul li {
+ font-size: 1rem;
+ color: #555;
+ line-height: 1.6;
+}
+
+.privacy-policy-section a:hover {
+ text-decoration: underline;
+ color: #0056a3;
+}
diff --git a/frontend/src/Pages/PrivacyPolicy.jsx b/frontend/src/Pages/PrivacyPolicy.jsx
new file mode 100644
index 0000000..f17ae7d
--- /dev/null
+++ b/frontend/src/Pages/PrivacyPolicy.jsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import './PrivacyPolicy.css';
+
+function PrivacyPolicy() {
+ return (
+
+
+
Privacy Policy
+
+
+
+
+
1. Introduction
+
+ Welcome to our website. We are committed to protecting your personal information
+ and your right to privacy. If you have any questions or concerns about our policy,
+ or our practices with regards to your personal information, please contact us.
+
+
+
+
+
2. Information We Collect
+
+ We collect personal information that you voluntarily provide to us when registering
+ on the website, expressing an interest in obtaining information about us or our
+ products and services, when participating in activities on the website, or otherwise
+ contacting us.
+
+
+ Personal Identification Information (Name, Email Address, Phone Number, etc.)
+ Payment Information (if applicable)
+ Technical Data (IP Address, Browser Type, etc.)
+
+
+
+
+
3. How We Use Your Information
+
+ We use the information we collect in the following ways:
+
+
+ To provide and manage services you have requested
+ To send promotional communications, with your consent
+ To improve our services and website functionality
+
+
+
+
+
4. Sharing Your Information
+
+ We may share your information in the following situations:
+
+
+ When you consent to the sharing of information
+ To comply with legal obligations or regulations
+ To protect the rights and safety of others
+
+
+
+
+
5. Your Privacy Rights
+
+ Depending on your location, you may have the right to access, update, or delete
+ your personal information. Please contact us to exercise your rights.
+
+
+
+
+
+ );
+}
+
+export default PrivacyPolicy;
diff --git a/frontend/src/Pages/Register.jsx b/frontend/src/Pages/Register.jsx
index 3f78939..e1bf2d0 100644
--- a/frontend/src/Pages/Register.jsx
+++ b/frontend/src/Pages/Register.jsx
@@ -2,40 +2,35 @@ import React, { useState, useEffect } from "react";
import logo from "../assets/stationsaarthi.svg";
import { useNavigate } from "react-router-dom";
import backicon from "../assets/svg/backicon.svg";
-import { GoogleLogin } from "@react-oauth/google";
-import { FaFacebook } from "react-icons/fa";
-import { jwtDecode } from "jwt-decode";
+import { FaFacebook, FaUser, FaPhone } from "react-icons/fa";
+import { MdAttachEmail, MdOutlinePassword } from "react-icons/md";
import { registerValidation } from "../validations/validation";
-import { FaUser , FaPhone } from "react-icons/fa";
-import { MdAttachEmail , MdOutlinePassword} from "react-icons/md";
-const Register = () => {
- useEffect(() => {
- document.title = 'Station Saarthi | Register';
- }, []);
+const Register = () => {
+ useEffect(() => {
+ document.title = 'Station Saarthi | Register';
+ }, []);
const navigate = useNavigate();
const LoginClick = () => navigate("/Login");
const HomeClick = () => navigate("/");
-
- const [username, setUserName] = useState(""); // Changed from name to username
+ const [username, setUserName] = useState("");
const [phoneNumber, setPhoneNumber] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmationMessage, setConfirmationMessage] = useState("");
- const [passwordStrength, setPasswordStrength] = useState(""); // State for password strength feedback
+ const [passwordStrength, setPasswordStrength] = useState("");
const [errors, setErrors] = useState({});
- const [passwordVisible, setPasswordVisible] = useState(false); // State for password visibility
-
+ const [passwordVisible, setPasswordVisible] = useState(false);
const handleRegister = async (e) => {
e.preventDefault();
try {
await registerValidation.validate(
- { username, password, phoneNumber, email }, // Updated validation call
+ { username, password, phoneNumber, email },
{ abortEarly: false }
);
setErrors({});
@@ -50,14 +45,14 @@ const Register = () => {
try {
const response = await fetch(
- "http://localhost:3000/api/register", "https://stationguidebackend.onrender.com",
+ "https://stationguidebackend.onrender.com/api/register",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
- name: username, // Updated from name to username
+ name: username,
phoneNumber: phoneNumber ? phoneNumber : "",
email,
password,
@@ -73,7 +68,7 @@ const Register = () => {
setConfirmationMessage(
"Your account is created successfully. Please login to access the website."
);
- setUserName(""); // Reset username
+ setUserName("");
setPhoneNumber("");
setEmail("");
setPassword("");
@@ -86,7 +81,6 @@ const Register = () => {
}
};
- // Use effect to clear the confirmation message after 3 seconds
useEffect(() => {
if (confirmationMessage) {
const timer = setTimeout(() => setConfirmationMessage(""), 3000);
@@ -94,7 +88,6 @@ const Register = () => {
}
}, [confirmationMessage]);
- // Function to check password strength
const checkPasswordStrength = (password) => {
if (password.length < 6) {
return "Weak";
@@ -110,76 +103,27 @@ const Register = () => {
}
};
- // Update password strength when password changes
useEffect(() => {
setPasswordStrength(checkPasswordStrength(password));
}, [password]);
- // Handle Google success
- const handleGoogleLoginSuccess = async (credentialResponse) => {
- const token = credentialResponse.credential;
-
- // Decode the token to extract user information
- const decoded = jwtDecode(token);
- console.log("Decoded Google Token:", decoded);
-
- try {
- const response = await fetch(
- "https://stationguide.onrender.com/api/register",
- {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- name: decoded.name,
- phoneNumber: phoneNumber ? phoneNumber : "",
- email: decoded.email,
- password: "",
- isGoogle: true,
- }),
- }
- );
-
- const data = await response.json();
-
- if (response.ok) {
- setConfirmationMessage(
- "Your account is created successfully. Please login to access the website."
- );
- setUserName(""); // Reset username
- setPhoneNumber("");
- setEmail("");
- setPassword("");
- } else {
- setConfirmationMessage(`Error: ${data.error}`);
- }
- } catch (error) {
- console.error("Error registering with Google:", error);
- }
- };
-
- // Handle Google failure
- const handleGoogleLoginFailure = () => {
- console.log("Google Sign-In failed");
- };
-
const togglePasswordVisibility = () => {
- setPasswordVisible(!passwordVisible); // Toggle password visibility
-};
+ setPasswordVisible(!passwordVisible);
+ };
return (
<>
-
+
{confirmationMessage && (
{confirmationMessage}
)}
-
-
-
+
+
+
+
-
-
-
-
- Already have an account?{" "}
(window.location.href = 'https://accounts.google.com')}
+ className="flex items-center justify-center w-full py-3 font-semibold text-white transition duration-300 ease-in-out transform bg-red-500 rounded-lg hover:bg-red-600 hover:scale-105"
>
- Login here
+
+ Sign in with Google
+
+
+
+ Already have an account?{" "}
+
+ Log In
+
+
+
>
);
};
-export default Register;
\ No newline at end of file
+export default Register;
diff --git a/frontend/src/Pages/Settings.jsx b/frontend/src/Pages/Settings.jsx
new file mode 100644
index 0000000..5e88630
--- /dev/null
+++ b/frontend/src/Pages/Settings.jsx
@@ -0,0 +1,105 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { FaUserCog, FaBell, FaUserAlt, FaLanguage, FaInfoCircle, FaPaperPlane } from 'react-icons/fa'; // Importing icons
+import { div } from 'framer-motion/client';
+
+const SettingsPage = () => {
+ const navigate = useNavigate();
+ const [notifications, setNotifications] = useState(true);
+ const [fontSize, setFontSize] = useState('medium');
+
+ const handleToggleNotifications = () => {
+ setNotifications(!notifications);
+ };
+
+ return (
+
+
Settings
+
+
+
+ {/* Account Management */}
+
+ Account Management
+
+
+ Change Password
+ Edit
+
+
+ Update Email
+ Edit
+
+
+ Delete Account
+ Delete
+
+
+
+
+ {/* Notification Settings */}
+
+
+ {/* Accessibility Options */}
+
+ Accessibility Options
+
+ Font Size:
+ setFontSize(e.target.value)}
+ className="p-2 border border-gray-300 rounded"
+ >
+ Small
+ Medium
+ Large
+
+
+
+
+ {/* Language Preferences */}
+
+ Language Preferences
+
+ English
+ Hindi
+ Other Languages
+
+
+
+ {/* About the App */}
+
+ About StationSaarthi
+
+ StationSaarthi is dedicated to enhancing your travel experience with real-time updates and helpful resources.
+ For more information, visit our Terms of Service and Privacy Policy .
+
+
+
+ {/* Feedback Section */}
+
+ Feedback
+
+ Submit Feedback
+
+
+
+ );
+};
+
+export default SettingsPage;
diff --git a/frontend/src/Pages/contributor.jsx b/frontend/src/Pages/contributor.jsx
index 1ed89a3..6ccc7d9 100644
--- a/frontend/src/Pages/contributor.jsx
+++ b/frontend/src/Pages/contributor.jsx
@@ -1,5 +1,7 @@
import React, { useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
+import backicon from '../assets/svg/backicon.svg';
+import { useNavigate } from 'react-router-dom';
const ContributorCard = ({ login, avatar_url, html_url, contributions, type }) => (
{
const [repoStats, setRepoStats] = useState({});
const [loading, setLoading] = useState(true);
const [email, setEmail] = useState('');
+ const navigate = useNavigate();
+ const HomeClick = () => navigate('/');
useEffect(() => {
document.title = 'Station Saarthi | Contributors';
@@ -97,6 +101,9 @@ const contributor = () => {
return (
{/* Hero Section */}
+
+
+
@@ -232,7 +239,7 @@ const contributor = () => {
Building a better future for public transportation.
- Home
+ Home
Documentation
GitHub
Contact
diff --git a/frontend/src/Pages/hamburger.jsx b/frontend/src/Pages/hamburger.jsx
index 821c5a6..f72fa36 100644
--- a/frontend/src/Pages/hamburger.jsx
+++ b/frontend/src/Pages/hamburger.jsx
@@ -1,7 +1,8 @@
-import React, { useState, useEffect, useRef } from 'react';
-import styled, { keyframes } from 'styled-components';
-import { FaArrowLeft, FaSearch, FaTimes } from 'react-icons/fa';
-import { useNavigate } from 'react-router-dom';
+import React, { useState, useEffect, useRef } from "react";
+import styled, { keyframes } from "styled-components";
+import { FaArrowLeft, FaSearch, FaTimes } from "react-icons/fa";
+import { useNavigate } from "react-router-dom";
+import { FaQuestionCircle } from "react-icons/fa";
const fadeIn = keyframes`
from {
@@ -39,9 +40,8 @@ const HamburgerContainer = styled.div`
}
`;
-
const Menu = styled.div`
- display: ${({ open }) => (open ? 'block' : 'none')};
+ display: ${({ open }) => (open ? "block" : "none")};
background-color: white;
position: absolute;
top: 0;
@@ -76,7 +76,8 @@ const HamburgerIcon = styled.div`
`;
const Bar1 = styled(MenuIconBar)`
- transform: ${({ open }) => (open ? 'rotate(-45deg) translate(-5px, 5px)' : 'rotate(0)')};
+ transform: ${({ open }) =>
+ open ? "rotate(-45deg) translate(-5px, 5px)" : "rotate(0)"};
`;
const Bar2 = styled(MenuIconBar)`
@@ -84,7 +85,8 @@ const Bar2 = styled(MenuIconBar)`
`;
const Bar3 = styled(MenuIconBar)`
- transform: ${({ open }) => (open ? 'rotate(45deg) translate(-5px, -5px)' : 'rotate(0)')};
+ transform: ${({ open }) =>
+ open ? "rotate(45deg) translate(-5px, -5px)" : "rotate(0)"};
`;
const BackButton = styled(FaArrowLeft)`
@@ -117,24 +119,21 @@ const ClearIcon = styled(FaTimes)`
const SearchContainer = styled.div`
display: flex;
align-items: center;
- justify-content:center !important;
+ justify-content: center !important;
position: fixed;
top: 10px;
- right: 16px;
- padding-block:6px;
- padding-inline:10px;
+ right: 70px;
+ padding-block: 6px;
+ padding-inline: 10px;
background-color: rgb(191 219 254);
border-radius: 30px;
-
`;
const SearchInput = styled.input`
-
-
background-color: transparent;
color: rgb(6 25 47);
outline: none;
- width: ${({ isFocused }) => (isFocused ? "200px" : "0px")};
+ width: ${({ isFocused }) => (isFocused ? "200px" : "0px")};
transition: width 0.4s ease;
opacity: ${({ show }) => (show ? 1 : 0)};
pointer-events: ${({ show }) => (show ? "auto" : "none")};
@@ -143,42 +142,45 @@ const SearchInput = styled.input`
}
`;
-const Hamburger = () => {
-
+const Hamburger = () => {
const navigate = useNavigate();
const HomeClick = () => {
- navigate('/');
+ navigate("/");
};
const SettingsClick = () => {
- navigate('/Settings');
+ navigate("/Settings");
};
const helpClick = () => {
- navigate('/Help');
+ navigate("/Help");
};
const aboutClick = () => {
- navigate('/About');
+ navigate("/About");
};
const Contactclick = () => {
- navigate('/ContactUs');
+ navigate("/ContactUs");
+ };
+ const privacyClick = () => {
+ navigate("/PrivacyPolicy"); // Navigate to Privacy and Policy page
+ };
+ const FaqClick = () => {
+ navigate("/Faq");
};
-
-
- const [open, setOpen] = useState(false);
- const [showSearch, setShowSearch] = useState(false);
- const [searchTerm, setSearchTerm] = useState('');
- const searchInputRef = useRef(null);
+ const [open, setOpen] = useState(false);
+ const [showSearch, setShowSearch] = useState(false);
+ const [searchTerm, setSearchTerm] = useState("");
+ const searchInputRef = useRef(null);
const [isFocused, setIsFocused] = useState(false);
const toggleMenu = () => {
setOpen((prev) => !prev);
};
-
+ 0.3;
const handleBack = () => {
setOpen(false);
@@ -193,20 +195,19 @@ const Hamburger = () => {
};
const clearSearch = () => {
- setSearchTerm('');
+ setSearchTerm("");
searchInputRef.current.focus();
};
const handleFocus = () => {
setIsFocused(true);
};
-
+
const handleBlur = (e) => {
if (!searchInputRef.current.contains(e.relatedTarget)) {
setIsFocused(false);
}
};
-
// Focus input when search is toggled on
useEffect(() => {
@@ -217,10 +218,8 @@ const Hamburger = () => {
return (
-
-
-
-
+
+
{
ref={searchInputRef}
value={searchTerm}
onChange={handleSearchChange}
- onFocus={handleFocus}
+ onFocus={handleFocus}
onBlur={handleBlur}
-
+ className="dark:bg-black dark:text-white dark:placeholder:text-gray-300"
/>
{showSearch && searchTerm && }
@@ -239,4 +238,4 @@ const Hamburger = () => {
);
};
-export default Hamburger;
\ No newline at end of file
+export default Hamburger;
diff --git a/frontend/src/Pages/schedule.jsx b/frontend/src/Pages/schedule.jsx
index a9983b2..9e4f121 100644
--- a/frontend/src/Pages/schedule.jsx
+++ b/frontend/src/Pages/schedule.jsx
@@ -1,166 +1,98 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState } from 'react';
import { IoArrowBack, IoSearchOutline } from 'react-icons/io5';
import { useNavigate } from 'react-router-dom';
-//import DatePicker from 'react-datepicker';
-import 'react-datepicker/dist/react-datepicker.css';
+import axios from 'axios';
const SchedulePage = () => {
- useEffect(() => {
- document.title = 'Station Saarthi | Schedule';
- }, []);
-
- const [trainNumber, setTrainNumber] = useState('22436');
- const [trainName, setTrainName] = useState('Vande Bharat');
- const [nextStation, setNextStation] = useState('Indore Jn.');
- const [services, setServices] = useState('-SELECT-');
- const [platformDetails, setPlatformDetails] = useState('Platform 3');
- const [coachDetails, setCoachDetails] = useState('A4');
- //const [date, setDate] = useState(null);
-
+ const [searchQuery, setSearchQuery] = useState('');
+ const [trainDetails, setTrainDetails] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
const navigate = useNavigate();
+ const searchTrain = async () => {
+ if (!searchQuery) {
+ setError('Please enter a train number to search');
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+
+ const apiKey = ""; // Enter your Indian Rail API key
+ const options = {
+ method: 'GET',
+ url: `https://indianrailapi.com/api/v2/TrainSchedule/apikey/${apiKey}/TrainNumber/${searchQuery}`,
+ };
+
+ try {
+ const response = await axios.request(options);
+ console.log("API Response Data:", response.data);
+
+ if (response.data.ResponseCode === "200") {
+ setTrainDetails(response.data.Route);
+ } else {
+ setError('No train details found');
+ }
+ } catch (error) {
+ console.error(error);
+ setError(error.message || 'An error occurred while fetching the train details');
+ } finally {
+ setLoading(false);
+ }
+ };
+
return (
-
+
-
-
-
navigate(-1)}
- className="flex items-center text-white hover:text-blue-200 transition-colors"
+
+
+
+ navigate(-1)}
+ className="flex items-center text-gray-800 transition-all duration-300 hover:text-white hover:bg-gray-800 border-2 border-gray-500 rounded-md px-2 py-1 shadow-sm text-sm"
>
-
- Back
+
+ Go Back
-
-
- Train Schedule
-
-
-
-
- {/* Search Input */}
-
-
- {/* Train Number Input */}
-
-
Train Number
-
- setTrainNumber(e.target.value)}
- className="w-full px-4 py-2 pr-10 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300"
- />
-
-
-
-
- {/* Train Name Input */}
-
-
Train Name
-
- setTrainName(e.target.value)}
- className="w-full px-4 py-2 pr-10 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300"
- />
-
-
-
-
-
+
Train Schedule
-
-
Next Station
+
+
+ Search by Train Number
+
+
setNextStation(e.target.value)}
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300"
+ placeholder="Enter train number..."
+ value={searchQuery}
+ onChange={(e) => setSearchQuery(e.target.value)}
+ className="w-full px-4 py-2 pr-10 border border-gray-300 rounded-lg"
/>
+
+ {error &&
{error}
}
+
-
- Services
- setServices(e.target.value)}
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300"
- >
- -SELECT-
- {/* @Select-- Add more options for SELECT */}
-
-
-
-
-
Platform Details
-
setPlatformDetails(e.target.value)}
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300"
- />
+ {loading &&
Loading...
}
+ {trainDetails && (
+
+ {trainDetails.map((stop) => (
+
+
{stop.StationName} ({stop.StationCode})
+
Arrival Time: {stop.ArrivalTime}
+
Departure Time: {stop.DepartureTime}
+
Distance: {stop.Distance} km
+
+ ))}
+ )}
-
- Coach Details
- setCoachDetails(e.target.value)}
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300"
- required
- >
- Select a coach
- GN - Unreserved
- SL - Sleeper
- 3A - AC 3-Tier
- 2A - AC 2-Tier
- 1A - First class AC
- CC - AC Chair Car
- EC - Executive Chair Car
- EA - Executive Anubhuti
- 2S - Second Sitting
- FC - First Class
-
-
-
-
- {/*
-
Date
-
- {/* setDate(date)}
- dateFormat="dd/MM/yyyy"
- placeholderText="DD/MM/YY"
- className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-300"
- popperClassName="z-50"
- /> }
-
-
*/}
-
-
-
- Get Directions
+
+ Search Train
diff --git a/frontend/src/Pages/stations.jsx b/frontend/src/Pages/stations.jsx
index c194f35..e874cea 100644
--- a/frontend/src/Pages/stations.jsx
+++ b/frontend/src/Pages/stations.jsx
@@ -1,32 +1,31 @@
-
-import React, { useState , useEffect} from "react";
-
-import { FaTrain } from "react-icons/fa"; // Using FontAwesome train icon
-import { AiFillCaretDown, AiFillCaretUp, AiFillStar, AiOutlineStar } from "react-icons/ai"; // Star icons for favorites
+import React, { useState, useEffect } from "react";
+import { FaTrain } from "react-icons/fa";
+import { AiFillStar, AiOutlineStar } from "react-icons/ai";
import { useNavigate } from "react-router-dom";
import backicon from "../assets/svg/backicon.svg";
-import { div, h1 } from "framer-motion/client";
-import allStations from "../dataset/stations.js"
-
+import allStations from "../dataset/stations.js";
const RailwayStations = () => {
-
useEffect(() => {
- document.title = 'Station Saarthi | Stations';
+ document.title = 'Station Saarthi | Stations';
}, []);
-
- // Comprehensive list of railway stations with zones
-
const navigate = useNavigate();
-
const HomeClick = () => {
navigate("/"); // Navigates to the home page
};
const [stations, setStations] = useState(allStations);
+ const [searchTerm, setSearchTerm] = useState("");
+ const [favorites, setFavorites] = useState([]);
+ const [selectedZone, setSelectedZone] = useState("All");
+ const [loading, setLoading] = useState(false);
+ // Pagination States
+ const [currentPage, setCurrentPage] = useState(1); // Current page
+ const [stationsPerPage] = useState(30); // Increased the number of stations per page to 20
+ // Define the zones array
const zones = [
["All", "All"],
["ECOR", "EAST COAST RAILWAY"],
@@ -45,18 +44,13 @@ const RailwayStations = () => {
["WR", "WESTERN RAILWAY"],
["BR", "BANGLADESH RAILWAY"],
["CPT", "Kolkata Port Trust Rly."],
- ["DFCR", "DEDICATED FREIGHT CORRIDO"],
+ ["DFCR", "DEDICATED FREIGHT CORRIDOR"],
["CP", "CHENNAI PORT TRUSTRAILWAY"],
["CR", "CENTRAL RAILWAY"],
["ECR", "EAST CENTRAL RAILWAY"],
["NPLR", "NEPAL RAILWAY"],
["MRK", "METRO RAILWAY KOLKATA"],
];
- const [searchTerm, setSearchTerm] = useState("");
- const [favorites, setFavorites] = useState([]);
- const [selectedZone, setSelectedZone] = useState("All");
- const [loading, setLoading] = useState(false);
- const [showFavorites, setShowFavorites] = useState(false);
// Function to toggle favorite stations
const toggleFavorite = (station) => {
@@ -64,11 +58,10 @@ const RailwayStations = () => {
setFavorites(favorites.filter((fav) => fav !== station));
} else {
setFavorites([...favorites, station]);
- console.log(favorites);
}
};
- // Filter stations based on search term and selected state
+ // Filter stations based on search term and selected zone
const filteredStations = stations.filter((station) => {
const matchesSearch = station.name
.toLowerCase()
@@ -78,14 +71,57 @@ const RailwayStations = () => {
return matchesSearch && matchesState;
});
+ // Paginate stations: get the stations to display for the current page
+ const indexOfLastStation = currentPage * stationsPerPage;
+ const indexOfFirstStation = indexOfLastStation - stationsPerPage;
+ const currentStations = filteredStations.slice(indexOfFirstStation, indexOfLastStation);
+
+ // Calculate total number of pages
+ const totalPages = Math.ceil(filteredStations.length / stationsPerPage);
+
+ // Handle page change
+ const paginate = (pageNumber) => setCurrentPage(pageNumber);
+
+ // Handle next and previous button clicks
+ const handlePrev = () => {
+ if (currentPage > 1) {
+ setCurrentPage(currentPage - 1);
+ }
+ };
+
+ const handleNext = () => {
+ if (currentPage < totalPages) {
+ setCurrentPage(currentPage + 1);
+ }
+ };
+
+ // Get pagination buttons (limit the number of visible page numbers)
+ const getPaginationRange = () => {
+ const range = [];
+ const maxButtonsToShow = 5; // Limit to 5 page numbers shown at once
+
+ // Display the first page, last page, and some pages in between
+ let start = Math.max(currentPage - Math.floor(maxButtonsToShow / 2), 1);
+ let end = Math.min(start + maxButtonsToShow - 1, totalPages);
+
+ // Adjust the range if there are too few pages before the current page
+ if (end - start + 1 < maxButtonsToShow) {
+ start = Math.max(end - maxButtonsToShow + 1, 1);
+ }
+
+ // Push the page numbers into the range array
+ for (let i = start; i <= end; i++) {
+ range.push(i);
+ }
+
+ return range;
+ };
+
useEffect(() => {
setLoading(true);
- fetch("http://localhost:3000/api/all-stations" , "https://stationguidebackend.onrender.com")
+ fetch("http://localhost:3000/api/all-stations")
+ .then((e) => e.json())
.then((e) => {
- return e.json();
- })
- .then((e) => {
- console.log(e);
setStations(e);
})
.catch((err) => {
@@ -99,7 +135,7 @@ const RailwayStations = () => {
if (loading) {
return (
);
}
@@ -108,18 +144,18 @@ const RailwayStations = () => {
{/* Header Section */}
-
-
-
+
+
+
-
+
Railway Stations
Find and explore railway stations across India
-
+
{/* Main Content: Stations Grid */}
{/* Search Bar and State Filter */}
@@ -143,12 +179,12 @@ const RailwayStations = () => {
))}
-
+
{/* Stations Grid */}
- {filteredStations.length > 0 ? (
- filteredStations.map((station, index) => (
+ {currentStations.length > 0 ? (
+ currentStations.map((station, index) => (
{
)}
+
+ {/* Pagination */}
+
+
+ Prev
+
+
+ {getPaginationRange().map((page) => (
+ paginate(page)}
+ className={`px-4 py-2 mx-1 rounded-md ${
+ currentPage === page
+ ? "bg-blue-500 text-white"
+ : "bg-gray-200 text-gray-700"
+ }`}
+ >
+ {page}
+
+ ))}
+
+
+ Next
+
+
-
- {/* Favorites Section - Moved to the Last */}
+
Your Favorite Stations
@@ -216,7 +284,6 @@ const RailwayStations = () => {
);
-
};
export default RailwayStations;
diff --git a/frontend/src/assets/station.png b/frontend/src/assets/station.png
new file mode 100644
index 0000000..ae46f61
Binary files /dev/null and b/frontend/src/assets/station.png differ
diff --git a/frontend/src/components/Footer.jsx b/frontend/src/components/Footer.jsx
new file mode 100644
index 0000000..cf81af9
--- /dev/null
+++ b/frontend/src/components/Footer.jsx
@@ -0,0 +1,14 @@
+
+import React from 'react';
+import { Link } from 'react-router-dom';
+
+const Footer = () => {
+ return (
+
+ All rights reserved.
+ Privacy and Policy
+
+ );
+};
+
+export default Footer;
diff --git a/frontend/src/components/Settings.jsx b/frontend/src/components/Settings.jsx
index 8a9232f..7db66e1 100644
--- a/frontend/src/components/Settings.jsx
+++ b/frontend/src/components/Settings.jsx
@@ -1,24 +1,158 @@
-import React from 'react';
-import { useNavigate } from 'react-router-dom';
-import backicon from '../assets/svg/backicon.svg';
-const Settings = () => {
- const navigate = useNavigate();
+import React, { useState } from 'react';
+export default function Settings() {
+ const [activeSection, setActiveSection] = useState('account');
+
+ const sections = [
+ { id: 'account', label: 'Account Settings' },
+ { id: 'privacy', label: 'Privacy' },
+ { id: 'notifications', label: 'Notifications' },
+ { id: 'security', label: 'Security' },
+ { id: 'display', label: 'Display & Accessibility' },
+ ];
-const HomeClick = () => {
- navigate('/'); // Navigates to the home page
- };
return (
- <>
-
-
-
-
-
Settings Page
-
+
+ {/* Sidebar */}
+
+
Settings
+
+ {sections.map((section) => (
+ setActiveSection(section.id)}
+ >
+ {section.label}
+
+ ))}
+
+
+
+ {/* Main Content */}
+
+ {/* Account Settings */}
+ {activeSection === 'account' && (
+
+ )}
+
+ {/* Privacy Settings */}
+ {activeSection === 'privacy' && (
+
+
Privacy Settings
+
+ Profile Visibility
+
+ Public
+ Friends Only
+ Private
+
+
+
+ Last Seen
+
+ Everyone
+ Friends Only
+ No One
+
+
+
+ Location Sharing
+
+ Enabled
+ Disabled
+
+
+
+ )}
+
+ {/* Notification Settings */}
+ {activeSection === 'notifications' && (
+
+ )}
+
+ {/* Security Settings */}
+ {activeSection === 'security' && (
+
+
Security Settings
+
+ Two-Factor Authentication
+ Enable 2FA
+
+
+
+ Send alerts for unrecognized logins
+
+
+
+ Keep me signed in on trusted devices
+
+
+ )}
+
+ {/* Display & Accessibility Settings */}
+ {activeSection === 'display' && (
+
+
Display & Accessibility
+
+ Theme
+
+ Light
+ Dark
+ System Default
+
+
+
+ Font Size
+
+ Small
+ Medium
+ Large
+
+
+
+
+ Enable high contrast mode
+
+
+ )}
+
- >
);
-};
-
-export default Settings;
\ No newline at end of file
+}
diff --git a/frontend/src/components/Stats.css b/frontend/src/components/Stats.css
new file mode 100644
index 0000000..7ddecf0
--- /dev/null
+++ b/frontend/src/components/Stats.css
@@ -0,0 +1,40 @@
+
+
+.stats-section {
+ display: flex; /* Keep items in a single row */
+ justify-content: space-between; /* Space items evenly */
+ padding: 20px;
+}
+
+.stat-item {
+ text-align: center; /* Center content within each item */
+ flex: 1 1 45%; /* Allow items to take 45% of the row space */
+ margin: 10px; /* Add margin for spacing */
+}
+
+.stat-number {
+ font-size: 2rem; /* Default size for numbers */
+ font-weight: 600;
+}
+
+.stat-title {
+ margin-top: 10px;
+ font-size: 1rem; /* Default size for titles */
+ color: #555;
+}
+
+/* Responsive styles */
+@media (max-width: 768px) {
+ .stat-number {
+ font-size: 1rem; /* Reduced size for numbers on smaller screens */
+ }
+
+ .stat-title {
+ font-size: 0.75rem; /* Reduced size for titles on smaller screens */
+ }
+
+ .stats-section {
+ padding: 0px;
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/src/components/Stats.jsx b/frontend/src/components/Stats.jsx
new file mode 100644
index 0000000..8ccd15d
--- /dev/null
+++ b/frontend/src/components/Stats.jsx
@@ -0,0 +1,48 @@
+import React, { useState } from 'react';
+import CountUp from 'react-countup';
+import VisibilitySensor from 'react-visibility-sensor';
+import './Stats.css';
+
+const Stats = () => {
+ const [viewed, setViewed] = useState({
+ stationsCovered: false,
+ activeUsers: false,
+ totalBookings: false,
+ feedbackRatings: false,
+ });
+
+ return (
+
+ setViewed(prev => ({ ...prev, stationsCovered: true }))} />
+ setViewed(prev => ({ ...prev, activeUsers: true }))} />
+ setViewed(prev => setViewed(prev => ({ ...prev, totalBookings: true })))} />
+ setViewed(prev => ({ ...prev, feedbackRatings: true }))} />
+
+ );
+};
+
+const StatItem = ({ title, end, viewed, setViewed }) => (
+
+
isVisible && setViewed()}>
+ {({ isVisible }) => (
+
+ {viewed || isVisible ? (
+ // Use CountUp with a formatted decimal display
+
+ ) : (
+ end
+ )}
+
+ )}
+
+
{title}
+
+);
+
+export default Stats;
diff --git a/frontend/src/components/TeamSection.jsx b/frontend/src/components/TeamSection.jsx
new file mode 100644
index 0000000..72cfaba
--- /dev/null
+++ b/frontend/src/components/TeamSection.jsx
@@ -0,0 +1,159 @@
+import React, { useState, useEffect, useCallback } from 'react';
+import { ChevronLeft, ChevronRight, Star } from 'lucide-react';
+import { useMediaQuery } from 'react-responsive';
+
+const teamMembers = [
+ {
+ name: 'Rajesh Kumar',
+ role: 'Technology Lead',
+ image: 'https://media.istockphoto.com/id/613557584/photo/portrait-of-a-beautifull-smiling-man.jpg?s=612x612&w=0&k=20&c=hkCg5CrmTKOApePbPOyo1U9GexEfIJOJqoLXJIvcN8E=', // Add actual image URL
+ quote: 'Passionate about technology and travel.',
+ bio: 'With over 10 years of experience in software development, Rajesh leads our tech initiatives to enhance the travel experience.',
+ },
+ {
+ name: 'Anita Desai',
+ role: 'User Experience Designer',
+ image: 'https://www.stylecraze.com/wp-content/uploads/2013/05/Most-Beautiful-Women-In-India.jpg', // Add actual image URL
+ quote: 'Designing for users is my passion.',
+ bio: 'Anita specializes in creating user-friendly interfaces that simplify interactions and enhance accessibility.',
+ },
+ {
+ name: 'Vikram Singh',
+ role: 'Operations Manager',
+ image: 'https://english.cdn.zeenews.com/sites/default/files/2017/11/17/639329-indian-men.jpg', // Add actual image URL
+ quote: 'Optimizing processes for better efficiency.',
+ bio: 'Vikram ensures that our operations run smoothly, focusing on delivering top-notch services to travelers.',
+ },
+ {
+ name: 'Rekha Sharma',
+ role: 'UX/UI Designer',
+ image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQJv1aDBUeruN6ZJwt5VqNHQx1UfUM8wShdEjGRAvW1lQxCAMG4cTgUX_ekZXDKHbAg8wQ&usqp=CAU',
+ quote: 'Creating user-centric designs.',
+ bio: 'Rekha ensures our interfaces are not only beautiful but also intuitive for users.'
+ },
+ {
+ name: 'Suresh Mehta',
+ role: 'Customer Support Lead',
+ image: 'https://cdn.openart.ai/stable_diffusion/18d45fc8e03d0f93cb1b170c810720b55d1822c7_2000x2000.webp',
+ quote: 'Ensuring a smooth journey for every passenger.',
+ bio: 'Suresh leads our customer support team, dedicated to resolving queries efficiently.'
+ },
+ // Add more team member objects as needed
+];
+
+// Duplicate the first and last members for infinite scroll effect
+const infiniteTeamMembers = teamMembers;
+
+const TeamCard = ({ member }) => (
+
+
+
+
+
+
{member.name}
+
{member.role}
+
+
+
"{member.quote}"
+
{member.bio}
+
+
+);
+
+const TeamSection = () => {
+ const [currentIndex, setCurrentIndex] = useState(1); // Start at the first real member
+ const [isTransitioning, setIsTransitioning] = useState(false);
+ const isSmallScreen = useMediaQuery({ query: '(max-width: 640px)' });
+ const isLargeScreen = useMediaQuery({ query: '(min-width: 641px)' });
+
+ const teamWidth = isSmallScreen ? 100 : 100 / 3;
+
+ const nextMember = useCallback(() => {
+ setIsTransitioning(true);
+ setCurrentIndex((prevIndex) => {
+ if (prevIndex === infiniteTeamMembers.length - 2) {
+ setTimeout(() => {
+ setIsTransitioning(false);
+ setCurrentIndex(1);
+ }, 500);
+ return prevIndex;
+ }
+ return prevIndex + 1;
+ });
+ }, []);
+
+ const prevMember = useCallback(() => {
+ setIsTransitioning(true);
+ setCurrentIndex((prevIndex) => {
+ if (prevIndex === 1) {
+ setTimeout(() => {
+ setIsTransitioning(false);
+ setCurrentIndex(infiniteTeamMembers.length - 2);
+ }, 500);
+ return prevIndex;
+ }
+ return prevIndex - 1;
+ });
+ }, []);
+
+ useEffect(() => {
+ const timer = setInterval(nextMember, 4000);
+ return () => clearInterval(timer);
+ }, [nextMember]);
+
+ return (
+
+
+
+ Meet Our Team
+
+
+ Our diverse team of professionals is driven by a passion for innovation. With expertise
+ spanning technology, transportation, and user experience design, we are dedicated to
+ making railway stations smarter, more efficient, and more enjoyable for every passenger.
+
+
+
+
+ {infiniteTeamMembers.map((member, index) => (
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+ {infiniteTeamMembers
+ .slice(1, isLargeScreen ? infiniteTeamMembers.length-1 : infiniteTeamMembers.length)
+ .map((_, index) => (
+
setCurrentIndex(index + 1)}
+ className={`w-2 h-2 mx-1 rounded-full cursor-pointer transition-colors duration-200 ${index + 1 === currentIndex ? 'bg-blue-600' : 'bg-gray-300'}`}
+ />
+ ))}
+
+
+
+ );
+};
+
+export default TeamSection;
diff --git a/frontend/src/components/ThemeToggle.jsx b/frontend/src/components/ThemeToggle.jsx
new file mode 100644
index 0000000..d7d0c43
--- /dev/null
+++ b/frontend/src/components/ThemeToggle.jsx
@@ -0,0 +1,32 @@
+import { FaSun, FaMoon } from 'react-icons/fa';
+import useDarkMode from '../hooks/useDarkMode';
+import "../../src/index.css";
+
+const ThemeSwitcher = () => {
+ const [theme, setTheme] = useDarkMode();
+ const isDarkMode = theme === 'dark';
+
+ return (
+
+
+ setTheme(isDarkMode ? 'light' : 'dark')}
+ />
+
+
+ {/* Sun Icon for Light Mode */}
+
+
+ {/* Moon Icon for Dark Mode */}
+
+
+
+
+
+ );
+};
+
+export default ThemeSwitcher;
\ No newline at end of file
diff --git a/frontend/src/components/about.jsx b/frontend/src/components/about.jsx
deleted file mode 100644
index e165550..0000000
--- a/frontend/src/components/about.jsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import React from 'react'; // Importing React
-import { useNavigate } from 'react-router-dom'; // Importing navigation function
-import backicon from '../assets/svg/backicon.svg'; // Importing back icon asset
-
-// About component
-const About = () => {
- // UseNavigate hook for navigation
- const navigate = useNavigate();
-
- // Function to handle home button click
- const HomeClick = () => {
- // Navigates to the home page when back button is clicked
- navigate('/');
- };
-
- // Return JSX structure
- return (
-
-
- {/* Back button to navigate to home */}
-
-
-
-
- {/* Main Heading */}
-
- ABOUT US
-
-
- {/* Introduction Section */}
-
- Welcome to
-
- StationSaarthi
- ,
- your one-stop platform designed to elevate your Indian Railway Station experience.
- With cutting-edge technology and user-friendly design, we aim to provide smooth and efficient
- travel assistance for all passengers.
-
-
- {/* Our Mission Section */}
-
-
- Our Mission
-
-
- At
-
- StationSaarthi
- ,
- our mission is to simplify the railway station experience by integrating advanced technology
- and providing real-time, actionable information to every traveler.
- We are committed to enhancing travel convenience for all.
-
-
-
- {/* Our Vision Section */}
-
-
- Our Vision
-
-
- Our vision is a future where every journey is hassle-free.
- We strive to create a travel ecosystem that connects passengers, railways, and services
- through seamless digital integration.
-
-
-
- {/* What We Offer Section */}
-
-
- What We Offer
-
-
- With
-
- StationSaarthi
- ,
- you get access to:
-
- Real-time train updates and notifications
- Interactive station maps for easy navigation
- Personalized travel recommendations
- Multi-language support to cater to diverse passengers
- Accessible services for differently-abled travelers
-
-
-
-
- {/* Why Choose Us Section */}
-
-
- Why Choose Us?
-
-
-
- StationSaarthi
-
- is more than a service; it's a commitment to revolutionizing your railway station experience.
- We believe in technology's power to enhance every aspect of your journey, ensuring safety,
- comfort, and convenience at every step.
-
-
-
- {/* Our Team Section */}
-
-
- Meet the Team
-
-
- Our diverse team of professionals is driven by a passion for innovation.
- With expertise spanning technology, transportation, and user experience design,
- we are dedicated to making railway stations smarter, more efficient, and more
- enjoyable for every passenger.
-
-
-
- {/* Footer */}
-
-
Β© 2024 StationSaarthi | All rights reserved
-
-
- );
-};
-
-// Exporting the About component for use in other parts of the app
-export default About;
diff --git a/frontend/src/components/navbar.jsx b/frontend/src/components/navbar.jsx
index 493ead9..8f23d4e 100644
--- a/frontend/src/components/navbar.jsx
+++ b/frontend/src/components/navbar.jsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
-import { FaBars, FaTimes, FaUser, FaHandsHelping, FaBell, FaStar, FaCreditCard, FaInfoCircle } from 'react-icons/fa';
+import { FaBars, FaTimes, FaUser, FaHandsHelping, FaBell, FaStar, FaCreditCard, FaInfoCircle, FaQuestionCircle } from 'react-icons/fa';
import { IoSettings } from "react-icons/io5";
-import { useNavigate } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
import axios from 'axios'; // Import axios
const Navbar = () => {
@@ -80,10 +80,19 @@ const Navbar = () => {
setIsOpen(false);
};
+
const handleAboutUsClick = () => {
navigate('/about');
setIsOpen(false);
};
+ const handleOpenComplain =() =>{
+ navigate('/complain');
+ setIsOpen(false);
+ }
+ const handleFaqClick = () => {
+ navigate('/Faq');
+ setIsOpen(false);
+ };
const handleOpenModal = () => {
setIsModalOpen(true);
@@ -92,66 +101,142 @@ const Navbar = () => {
return (
<>
{/* Navigation Toggle for All Screens (Mobile and Larger Screens) */}
-
+
{isOpen ? : }
-
- {/* Sidebar Navigation (Covers 25% on larger screens, full width on mobile) */}
-
-
- {/* Close Button inside Sidebar */}
-
-
-
-
+ {/* Google Translate widget with dynamic z-index */}
+
+
+
- {/* Sidebar Menu Content */}
-
- {/* Profile Section */}
-
-
Yatree
-
5.0 β
-
- {/* Menu Items */}
-
-
-
-
- Make a Payment
-
-
-
- Help and Support
-
-
-
- Emergency
-
-
-
- About Us
-
-
-
- Feedback
-
-
-
- Settings
-
-
-
-
- {/* Footer */}
-
- App version 1.0.0.0
-
-
-
+{/* Sidebar Navigation */}
+
+
+ {/* Close Button */}
+
+
+
+
+
+
+ {/* Profile Section */}
+
+
+ {/* Sidebar Content with Scrollable Area */}
+
+
+
+ {/* Menu items */}
+
+
+ Make a Payment
+
+
+
+ Help and Support
+
+
+
+ Emergency
+
+
+
+ About Us
+
+
+
+ Feedback
+
+
+
+ Complain
+
+
+
+ Settings
+
+
+
+ FAQ
+
+
+
+
+
+ {/* Footer */}
+
+
+
{/* Rating Modal */}
{isModalOpen && (
diff --git a/frontend/src/components/popup.jsx b/frontend/src/components/popup.jsx
index 37495e7..d24c3f8 100644
--- a/frontend/src/components/popup.jsx
+++ b/frontend/src/components/popup.jsx
@@ -28,10 +28,10 @@ const Popup = () => {
return (
isVisible && (
-
-
+
+
X
@@ -40,13 +40,13 @@ const Popup = () => {
-
Welcome to Station Saarthi
-
Travel without stress. Sign in now!
+
Welcome to Station Saarthi
+
Travel without stress. Sign in now!
setEmail(e.target.value)}
@@ -54,12 +54,12 @@ const Popup = () => {
/>
Sign me up!
-
+
By signing in, I agree to Station Saarthi's{' '}
Terms of Service and{' '}
Privacy Policy .
diff --git a/frontend/src/hooks/useDarkMode.js b/frontend/src/hooks/useDarkMode.js
new file mode 100644
index 0000000..b391abf
--- /dev/null
+++ b/frontend/src/hooks/useDarkMode.js
@@ -0,0 +1,18 @@
+import { useState, useEffect } from 'react';
+
+const useDarkMode = () => {
+ const [theme, setTheme] = useState(() => localStorage.getItem('theme') || 'light');
+
+ useEffect(() => {
+ const root = document.documentElement;
+ const isDark = theme === 'dark';
+ root.classList.toggle('dark', isDark);
+ console.log(`Theme set to ${theme}, dark mode is ${isDark ? 'enabled' : 'disabled'}`);
+ localStorage.setItem('theme', theme);
+ }, [theme]);
+
+
+ return [theme, setTheme];
+};
+
+export default useDarkMode;
\ No newline at end of file
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
index f802306..0fa203a 100644
--- a/frontend/src/main.jsx
+++ b/frontend/src/main.jsx
@@ -7,6 +7,18 @@ import { GoogleOAuthProvider } from "@react-oauth/google"
const clientId = import.meta.env.VITE_OAUTH_CLIENT_ID
+if ('serviceWorker' in navigator) {
+ window.addEventListener('load', () => {
+ navigator.serviceWorker.register('/service-worker.js')
+ .then(registration => {
+ console.log('ServiceWorker registration successful');
+ })
+ .catch(err => {
+ console.log('ServiceWorker registration failed: ', err);
+ });
+ });
+}
+
createRoot(document.getElementById('root')).render(
diff --git a/frontend/src/metadata.jsx b/frontend/src/metadata.jsx
new file mode 100644
index 0000000..4d1766c
--- /dev/null
+++ b/frontend/src/metadata.jsx
@@ -0,0 +1,45 @@
+import React from "react";
+
+const Metadata = () => {
+ return (
+ <>
+
+ Station Guide - Your Platform Guide
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default Metadata;
diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js
index 6bdcac8..52339c9 100644
--- a/frontend/tailwind.config.js
+++ b/frontend/tailwind.config.js
@@ -1,9 +1,10 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
+ darkMode: 'class',
theme: {
- extend: {},
+ extend: {
+ },
},
plugins: [],
-}
-
+};