Commit 64df307a by Sujeeth AV

Fixed signup page routing issue and updated LoginPage.jsx

parent 0b1fbd2e
...@@ -135,7 +135,11 @@ ...@@ -135,7 +135,11 @@
{ {
"userId": "9677655288", "userId": "9677655288",
"seats": [ "seats": [
"A1" "A4",
"A5",
"A6",
"E5",
"E6"
], ],
"status": "booked", "status": "booked",
"id": "4271" "id": "4271"
...@@ -154,8 +158,10 @@ ...@@ -154,8 +158,10 @@
{ {
"userId": "9500403346", "userId": "9500403346",
"seats": [ "seats": [
"F3", "C5",
"F4" "C6",
"C7",
"C8"
], ],
"status": "booked", "status": "booked",
"id": "b4fe" "id": "b4fe"
...@@ -163,8 +169,8 @@ ...@@ -163,8 +169,8 @@
{ {
"userId": "9976051171", "userId": "9976051171",
"seats": [ "seats": [
"F1", "A1",
"F2" "A2"
], ],
"status": "booked", "status": "booked",
"id": "40ef" "id": "40ef"
......
...@@ -7,13 +7,12 @@ ...@@ -7,13 +7,12 @@
body { body {
background-color: #303fb6; background-color: #303fb6;
font-family: "Poppins", sans-serif; font-family: "Poppins", sans-serif;
min-height: 50svh; min-height: 100svh;
height: 100svh;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 1rem;
margin: 0; margin: 0;
padding: 0;
} }
h2 { h2 {
font-size: 1.5rem; font-size: 1.5rem;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -2,24 +2,29 @@ ...@@ -2,24 +2,29 @@
"name": "seat", "name": "seat",
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview", "preview": "vite preview",
"storybook": "storybook dev -p 6006", "storybook": "storybook dev -p 6006",
"build-storybook": "storybook build" "build-storybook": "storybook build",
"start:server": "json-server --watch db.json --port 3001 --host 0.0.0.0"
}, },
"dependencies": { "dependencies": {
"axios": "^1.9.0", "axios": "^1.9.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"express": "^5.1.0",
"fireworks-js": "^2.10.8", "fireworks-js": "^2.10.8",
"json-server": "^0.17.4",
"json-server-auth": "^2.1.0",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-router-dom": "^7.6.2", "react-router-dom": "^7.6.2",
"react-toastify": "^11.0.5" "react-toastify": "^11.0.5",
"remark-gfm": "^4.0.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.25.0", "@eslint/js": "^9.25.0",
......
const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();
server.use(middlewares);
server.use(jsonServer.bodyParser);
server.get('/reserved-seats', (req, res) => {
const seats = router.db.get('seats')
.filter({ status: 'booked' })
.map(seat => ({
id: seat.id,
seats: seat.seats
}))
.value();
res.json(seats);
});
server.use(router);
const PORT = 3001;
server.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
});
import axios from "axios"; import axios from "axios";
const BASE_URL = "http://192.168.1.64:3001"; const BASE_URL = "http://192.168.1.64:3001";
export const loginUser = async (mobile) => { export const loginUser = async (mobile) => {
const res = await axios.get(`${BASE_URL}/users`, { const res = await axios.get(`${BASE_URL}/users`, {
params: { Mobile: mobile } params: { Mobile: mobile }
...@@ -61,3 +63,8 @@ export const getUserReservedSeats = async (userId) => { ...@@ -61,3 +63,8 @@ export const getUserReservedSeats = async (userId) => {
return record || null; return record || null;
}; };
export const getReservedSeatOnly=async()=>{
const response=await axios.get(`${BASE_URL}/reserved-seats`);
return response.data;
};
...@@ -11,14 +11,7 @@ function App() { ...@@ -11,14 +11,7 @@ function App() {
<ContextProvider> <ContextProvider>
<Routes> <Routes>
<Route path="/" element={<LoginPage />} /> <Route path="/" element={<LoginPage />} />
<Route <Route path="/signup" element={<LoginPage />} />
path="/signup"
element={
<ProtectedRoute>
<LoginPage />
</ProtectedRoute>
}
/>
<Route <Route
path="/seat-limit" path="/seat-limit"
element={ element={
...@@ -43,6 +36,8 @@ function App() { ...@@ -43,6 +36,8 @@ function App() {
</ProtectedRoute> </ProtectedRoute>
} }
/> />
<Route path="*" element={<Summary success={false} />} />
</Routes> </Routes>
</ContextProvider> </ContextProvider>
); );
......
src/Assets/Failed.png

261 KB | W: | H:

src/Assets/Failed.png

61.1 KB | W: | H:

src/Assets/Failed.png
src/Assets/Failed.png
src/Assets/Failed.png
src/Assets/Failed.png
  • 2-up
  • Swipe
  • Onion skin
src/Assets/Login.png

240 KB | W: | H:

src/Assets/Login.png

135 KB | W: | H:

src/Assets/Login.png
src/Assets/Login.png
src/Assets/Login.png
src/Assets/Login.png
  • 2-up
  • Swipe
  • Onion skin
import { Input } from "./Input"; import { Input } from "./Input";
export default { export default {
title: 'Base/Input', title: "Base/Input",
component: Input, component: Input,
tags: ['autodocs'], tags: ["autodocs"],
}; };
export const input={ export const input = {
render:(args)=><Input {...args}/>, render: (args) => <Input {...args} />,
args:{ args: {
placeholder:'Enter the Text', placeholder: "Enter the Text",
} type: "text",
} },
};
export const number={
render:(args)=><Input {...args}/>,
args:{ export const number = {
placeholder:'Enter Your Number', render: (args) => <Input {...args} />,
}
}
args: {
placeholder: "Enter Your Number",
type: "number",
},
};
...@@ -3,11 +3,13 @@ import { Header } from "../../Layout/Card/Header"; ...@@ -3,11 +3,13 @@ import { Header } from "../../Layout/Card/Header";
import { Input } from "../../Form/form/Input"; import { Input } from "../../Form/form/Input";
import { Button } from "../../Form/Button/Button"; import { Button } from "../../Form/Button/Button";
import styles from "./Login.module.css"; import styles from "./Login.module.css";
import { toast, ToastContainer } from "react-toastify";
import Home from "../../../Assets/Login.png"; import Home from "../../../Assets/Login.png";
import { FaPhoneAlt } from "react-icons/fa"; import { FaPhoneAlt } from "react-icons/fa";
import PropTypes from "prop-types";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
export const Login = ({ onClick, onSwitch }) => { export const Login = ({ title, onSubmit = () => {}, markdown, labels }) => {
const [value, setValue] = useState(""); const [value, setValue] = useState("");
const [islesser, setIsLesser] = useState(false); const [islesser, setIsLesser] = useState(false);
...@@ -19,43 +21,34 @@ export const Login = ({ onClick, onSwitch }) => { ...@@ -19,43 +21,34 @@ export const Login = ({ onClick, onSwitch }) => {
} }
}; };
const HandleButton = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
if (!value) {
toast.info("Please Enter Your Number");
return;
}
if (!/^[6-9]\d{9}$/.test(value)) {
toast.info("Invalid Number");
return;
}
if (value.length < 10) { if (value.length < 10) {
setIsLesser(true); setIsLesser(true);
toast.error("Mobile Number is less than 10"); return;
} else {
console.log("onClick prop:", onClick);
onClick({ mobile: value });
setIsLesser(false);
setValue("");
} }
onSubmit({ mobile: value });
setIsLesser(false);
setValue("");
}; };
const HandleKey = (e) => {
const handleKey = (e) => {
if (e.key === "Enter") { if (e.key === "Enter") {
HandleButton(e); handleSubmit(e);
} }
}; };
return ( return (
<> <>
<div className={styles.container}> <div className={`${styles.login} ${styles.round}`}>
<div className={`${styles.back} ${styles.round}`}> <Header title={title} className={styles.head} />
<Header title="Login Page" Color="#000" className={styles.head} /> <img src={Home} className={styles.img} alt="Login illustration" />
<img src={Home} className={styles.img} />
<div className={styles.form}> <div className={styles.form}>
<form onSubmit={handleSubmit}>
<div className={styles.inp}> <div className={styles.inp}>
<Input <Input
placeholder="Enter Your Mobile Number" placeholder={labels.mobilePlaceholder}
value={value} value={value}
onChange={InputChange} onChange={InputChange}
type="tel" type="tel"
...@@ -63,32 +56,41 @@ export const Login = ({ onClick, onSwitch }) => { ...@@ -63,32 +56,41 @@ export const Login = ({ onClick, onSwitch }) => {
min="0" min="0"
icon={FaPhoneAlt} icon={FaPhoneAlt}
required required
onKeyDown={HandleKey} onKeyDown={handleKey}
/> />
</div> </div>
{islesser && ( {islesser && (
<span className={styles.span}>Please enter 10 digits</span> <span className={styles.span}>{labels.mobileError}</span>
)} )}
<div className={styles.btn}> <div className={styles.btn}>
<Button <Button type="submit">{labels.submitBtnText}</Button>
children="Submit"
onClick={HandleButton}
// disabled={value.trim().length === 0}
/>
<div className={styles.foot}>
Don't have an account?{" "}
<span
style={{ color: "blue", cursor: "pointer" }}
onClick={onSwitch}
>
Sign Up
</span>
</div>
</div> </div>
</form>
<div className={styles.footer}>
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{markdown}
</ReactMarkdown>
</div> </div>
</div> </div>
<ToastContainer />
</div> </div>
</> </>
); );
}; };
Login.propTypes = {
onSubmit: PropTypes.func,
onSwitch: PropTypes.func,
markdown: PropTypes.string,
labels: PropTypes.shape({
submitBtnText: PropTypes.string,
mobilePlaceholder: PropTypes.string,
mobileInvalid: PropTypes.string,
mobileError: PropTypes.string,
mobileRequired: PropTypes.string,
title: PropTypes.string,
signUp: PropTypes.string,
accountLabel: PropTypes.string,
}),
};
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/icon?family=Material+Icons"); @import url("https://fonts.googleapis.com/icon?family=Material+Icons");
.container { .login {
min-height: 100vh; background: #ffff;
display: flex; padding: 1rem;
align-items: center;
justify-content: center;
}
.back {
background-color: #f7fafc;
padding: 2rem;
border-radius: 0.75rem; border-radius: 0.75rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
width: 100%;
max-width: 28rem;
text-align: center; text-align: center;
} }
.round { img {
border-radius: 0.75rem;
}
.head {
font-size: 1.875rem;
font-weight: 700;
color: #2d3748;
margin-bottom: 2rem;
}
.img {
width: 16rem;
height: auto; height: auto;
margin-bottom: 2rem; aspect-ratio: 4/3;
object-fit: contain;
max-width: 100%;
display: block;
} }
.form { .form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.3rem;
} }
.inp { .inp {
margin-bottom: 0.3rem; margin-bottom: 0;
} }
.span { .span {
...@@ -56,7 +37,7 @@ ...@@ -56,7 +37,7 @@
.btn { .btn {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.5rem; gap: 0.3rem;
} }
.foot { .foot {
...@@ -64,3 +45,11 @@ ...@@ -64,3 +45,11 @@
color: #4a5568; color: #4a5568;
margin-top: 1rem; margin-top: 1rem;
} }
.head {
color: #000;
}
.footer {
margin-top: 1rem;
}
...@@ -5,8 +5,7 @@ export default { ...@@ -5,8 +5,7 @@ export default {
component: Login, component: Login,
tags: ["autodocs"], tags: ["autodocs"],
argTypes: { argTypes: {
onClick: { action: "User" }, onSubmit: { action: "Submitted" },
onChange: { action: "change" },
}, },
parameters: { parameters: {
layout: "centered", layout: "centered",
...@@ -14,11 +13,15 @@ export default { ...@@ -14,11 +13,15 @@ export default {
}; };
export const login = { export const login = {
render: (args) => <Login {...args} />,
args: { args: {
value: "", value: "",
onLogin: (user) => { title: "Login",
console.log("login", user); markdown: `Don't have an account? [SignUp](/sign-up)`,
labels: {
mobilePlaceholder: "Enter Your Number",
submitBtnText: "Submit",
mobileError: "Enter 10 digits",
}, },
}, },
render: (args) => <Login {...args} />,
}; };
...@@ -3,12 +3,13 @@ import { Input } from "../../Form/form/Input"; ...@@ -3,12 +3,13 @@ import { Input } from "../../Form/form/Input";
import { Button } from "../../Form/Button/Button"; import { Button } from "../../Form/Button/Button";
import { Header } from "../../Layout/Card/Header"; import { Header } from "../../Layout/Card/Header";
import style from "./Styles.module.css"; import style from "./Styles.module.css";
import { ToastContainer } from "react-toastify";
import { toast } from "react-toastify";
import { FaPhoneAlt } from "react-icons/fa"; import { FaPhoneAlt } from "react-icons/fa";
import { TiSortAlphabetically } from "react-icons/ti"; import { TiSortAlphabetically } from "react-icons/ti";
export const Sign = ({
export const Sign = ({ onClick, onChange, onSwitch }) => { onSubmit,
onChange,
labels: { mobileplaceholder, nameplaceholder, btnLabel, titleLabel },
}) => {
const [num, setNum] = useState(""); const [num, setNum] = useState("");
const [name, setName] = useState(""); const [name, setName] = useState("");
...@@ -27,70 +28,55 @@ export const Sign = ({ onClick, onChange, onSwitch }) => { ...@@ -27,70 +28,55 @@ export const Sign = ({ onClick, onChange, onSwitch }) => {
onChange(e); onChange(e);
} }
}; };
const handleNewUser = () => { const handleNewUser = (e) => {
e.preventDefault();
console.log("signup page worked"); console.log("signup page worked");
if (!num || !name) { if (onSubmit) {
toast.error("Please enter both Name and Number "); onSubmit({ name, mobile: num });
return;
}
if (!/^[6-9]\d{9}$/.test(num)) {
toast.info("Please enter a valid 10-digit number");
return;
}
const confirmSignUp = window.confirm("Are you sure you want to Sign Up?");
if (!confirmSignUp) return;
console.log("Calling onClick:", { mobile: num, name });
if (onClick) {
onClick({ mobile: num, name });
} else {
console.log("onclick not defined in sign");
}
setName("");
setNum("");
if (onSwitch) {
onSwitch();
} }
}; };
return ( return (
<> <>
<div className={style.container}> <div className={style.container}>
<div className={style.block}> <div className={style.block}>
<div className={style.image}> <div className={style.image}>
<Header title="Sign-Up Page" Color="#000" className={style.head} /> <Header title={titleLabel} className={style.head} />
</div> </div>
<div className={style.signcontainer}> <div className={style.signcontainer}>
<div className={style.Inpbtn}> <form onSubmit={handleNewUser}>
<Input <div className={style.Inpbtn}>
placeholder="Enter Your Mobile Number" <Input
value={num} placeholder={mobileplaceholder}
onChange={Number} value={num}
type="text" onChange={Number}
pattern="[6-9][0-9]{9}" type="text"
min="0" pattern="[6-9][0-9]{9}"
icon={FaPhoneAlt} min="0"
/> icon={FaPhoneAlt}
</div> />
<div className={style.Inpname}> </div>
<Input <div className={style.Inpname}>
placeholder="Enter Your Name" <Input
value={name} placeholder={nameplaceholder}
onChange={Name} value={name}
type="text" onChange={Name}
maxLength={255} type="text"
icon={TiSortAlphabetically} maxLength={255}
/> icon={TiSortAlphabetically}
</div> />
<div className={style.signbtn}> </div>
<Button <div className={style.signbtn}>
children="Submit" <Button
size="medium" children={btnLabel}
primary="true" size="medium"
onClick={handleNewUser} primary="true"
/> type="submit"
</div> />
</div>
</form>
</div> </div>
</div> </div>
<ToastContainer />
</div> </div>
</> </>
); );
......
...@@ -11,4 +11,14 @@ export default { ...@@ -11,4 +11,14 @@ export default {
}, },
}; };
export const signUp = (args) => <Sign {...args} />; export const signUp = {
render: (args) => <Sign {...args} />,
args: {
labels: {
mobileplaceholder: "Enter Your Number",
nameplaceholder: "Enter Your Name",
btnLabel: "Submit",
titleLabel: "SignUp",
},
},
};
...@@ -12,22 +12,18 @@ ...@@ -12,22 +12,18 @@
background-color: #ffffff; background-color: #ffffff;
border-radius: 1rem; border-radius: 1rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
padding: 1.2rem; padding: 1rem;
max-width: 600px; max-width: 37.5rem;
width: 100%; width: 100%;
} }
.head {
color: #000;
}
.image { .image {
text-align: center; text-align: center;
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.head {
font-size: 2rem;
font-weight: bold;
color: #1f2937;
}
.signcontainer { .signcontainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
......
export const Header = ({ title, Color, className }) => { import styles from "./Header.module.css";
export const Header = ({ title, fontSize, ...props }) => {
return ( return (
<div className={className}> <div className={styles.head}>
<h2 style={{ color: Color }}>{title}</h2> <h2 style={{ fontSize }} {...props}>
{title}
</h2>
</div> </div>
); );
}; };
...@@ -4,7 +4,7 @@ import { MdHome, MdCheckCircle } from "react-icons/md"; ...@@ -4,7 +4,7 @@ import { MdHome, MdCheckCircle } from "react-icons/md";
import { RiArrowGoBackLine } from "react-icons/ri"; import { RiArrowGoBackLine } from "react-icons/ri";
import { Button } from "../Form/Button/Button"; import { Button } from "../Form/Button/Button";
import styles from "./Styles.module.css"; import styles from "./Styles.module.css";
import Success from "../../Assets/Success.png";
import Failed from "../../Assets/Failed.png"; import Failed from "../../Assets/Failed.png";
export const Summary = ({ success: propSuccess }) => { export const Summary = ({ success: propSuccess }) => {
...@@ -30,11 +30,6 @@ export const Summary = ({ success: propSuccess }) => { ...@@ -30,11 +30,6 @@ export const Summary = ({ success: propSuccess }) => {
Your tickets are ready. Enjoy the show! Your tickets are ready. Enjoy the show!
</p> </p>
<div className={styles.qrContainer}>
<img src={Success} alt="QR code" className={styles.qr} />
<p className={styles.qrNote}>Your Seat, Secured in Seconds</p>
</div>
{bookingInfo && ( {bookingInfo && (
<div className={styles.info}> <div className={styles.info}>
<div className={styles.row}> <div className={styles.row}>
...@@ -79,10 +74,6 @@ export const Summary = ({ success: propSuccess }) => { ...@@ -79,10 +74,6 @@ export const Summary = ({ success: propSuccess }) => {
) : ( ) : (
<div className={styles.error}> <div className={styles.error}>
<img src={Failed} alt="Failed" className={styles.symbol} /> <img src={Failed} alt="Failed" className={styles.symbol} />
<h2 className={styles.hdError}>Something Went Wrong</h2>
<p className={styles.timeStamp}>
Booked On: {new Date().toLocaleString()}
</p>
<Button onClick={onLogout} className={styles.homeBtn}> <Button onClick={onLogout} className={styles.homeBtn}>
<IoMdLogOut className={styles.icon} /> <IoMdLogOut className={styles.icon} />
<span>Back to Home</span> <span>Back to Home</span>
......
...@@ -3,16 +3,14 @@ ...@@ -3,16 +3,14 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-height: 100vh; margin: 2rem;
padding: 1rem; padding: 1rem;
margin: 1rem;
} }
.success { .success {
background-color: #ffffff; background-color: #ffffff;
padding: 2rem; padding: 2rem;
border-radius: 1.5rem; border-radius: 1.5rem;
max-width: 500px;
width: 100%; width: 100%;
text-align: center; text-align: center;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
...@@ -20,21 +18,21 @@ ...@@ -20,21 +18,21 @@
.error { .error {
background-color: #fff1f1; background-color: #fff1f1;
padding: 2rem; padding: 1.2rem;
border-radius: 1.5rem; border-radius: 1.5rem;
max-width: 500px; max-width: 50svh;
width: 100%; width: 100%;
text-align: center; text-align: center;
border: 1px solid #fca5a5;
box-shadow: 0 10px 25px rgba(239, 68, 68, 0.1);
} }
.symbol { .symbol {
font-size: 64px; font-size: 54px;
color: #22c55e; color: #22c55e;
margin-bottom: 1rem;
} }
.error .symbol {
max-width: 100%;
object-fit: contain;
}
.qr { .qr {
width: 128px; width: 128px;
height: 128px; height: 128px;
...@@ -50,20 +48,20 @@ ...@@ -50,20 +48,20 @@
} }
.qrNote { .qrNote {
font-size: 0.75rem; font-size: 0.69rem;
color: #6b7280; color: #6b7280;
margin-top: 0.5rem; margin-top: 0.5rem;
} }
.hd { .hd {
font-size: 1.5rem; font-size: 1rem;
font-weight: 600; font-weight: 600;
color: #1f2937; color: #1f2937;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.hdError { .hdError {
font-size: 1.25rem; font-size: 0.9rem;
font-weight: 600; font-weight: 600;
color: #dc2626; color: #dc2626;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
...@@ -71,12 +69,12 @@ ...@@ -71,12 +69,12 @@
.subtitle { .subtitle {
color: #4b5563; color: #4b5563;
margin-bottom: 2rem; font-size: 0.78rem;
} }
.info { .info {
margin-bottom: 2rem; margin-bottom: 1rem;
font-size: 0.875rem; font-size: 0.775rem;
} }
.row { .row {
...@@ -106,8 +104,8 @@ ...@@ -106,8 +104,8 @@
color: #4338ca; color: #4338ca;
padding: 0.25rem 0.75rem; padding: 0.25rem 0.75rem;
border-radius: 9999px; border-radius: 9999px;
font-size: 0.75rem; font-size: 0.6rem;
font-weight: 500; font-weight: 450;
} }
.downloadBtn { .downloadBtn {
...@@ -125,6 +123,7 @@ ...@@ -125,6 +123,7 @@
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
cursor: pointer; cursor: pointer;
font-size: 0.78rem;
} }
.downloadBtn:hover { .downloadBtn:hover {
...@@ -146,6 +145,7 @@ ...@@ -146,6 +145,7 @@
gap: 0.5rem; gap: 0.5rem;
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
cursor: pointer; cursor: pointer;
font-size: 0.78rem;
} }
.homeBtn:hover { .homeBtn:hover {
...@@ -153,17 +153,58 @@ ...@@ -153,17 +153,58 @@
} }
.icon { .icon {
font-size: 1.25rem; font-size: 1rem;
} }
.timeStamp { .timeStamp {
font-size: 0.875rem; font-size: 0.675rem;
color: #6b7280; color: #6b7280;
margin-bottom: 1rem;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.pageContainer { .pageContainer {
margin: 0; margin: 0;
margin-top: 4rem;
}
.symbol {
font-size: 64px;
margin-bottom: 1rem;
}
.icon {
font-size: 1.25rem;
}
.timeStamp {
font-size: 0.875rem;
margin-bottom: 1rem;
}
.seatPill {
font-size: 0.75rem;
font-weight: 500;
}
.info {
margin-bottom: 2rem;
font-size: 0.875rem;
}
.qrNote {
font-size: 0.75rem;
}
.hd {
font-size: 1.5rem;
font-weight: 600;
}
.hdError {
font-size: 1.25rem;
font-weight: 600;
}
.subtitle {
font-size: 1rem;
margin-bottom: 2rem;
}
.homeBtn,
.downloadBtn {
font-size: 1rem;
} }
} }
...@@ -7,10 +7,8 @@ import { toast } from "react-toastify"; ...@@ -7,10 +7,8 @@ import { toast } from "react-toastify";
const Counter = ({ onSubmit, className, onChange, onClick }) => { const Counter = ({ onSubmit, className, onChange, onClick }) => {
const [count, setCount] = useState(0); const [count, setCount] = useState(0);
console.log(onSubmit);
const Num = (e) => { const Num = (e) => {
const value = Number(e.target.value); const value = Number(e.target.value);
console.log("number", value);
setCount(value); setCount(value);
if (onChange) { if (onChange) {
onChange({ limit: value }); onChange({ limit: value });
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
width: 100%; width: 100%;
max-width: 15rem; max-width: 15rem;
background-color: #ffffff; background-color: #ffffff;
padding: 1.5rem; padding: 1rem;
border-radius: 1rem; border-radius: 1rem;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04); 0 10px 10px -5px rgba(0, 0, 0, 0.04);
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
.hd { .hd {
text-align: center; text-align: center;
margin-bottom: 1.5rem; margin-bottom: 1rem;
font-size: 1.125rem; font-size: 0.787rem;
font-weight: 500; font-weight: 250;
color: #000000; color: #000000;
} }
.block { .block {
margin-bottom: 1.5rem; margin-bottom: 0.5rem;
} }
.block input[type="number"] { .block input[type="number"] {
...@@ -72,6 +72,14 @@ ...@@ -72,6 +72,14 @@
@media (min-width: 768px) { @media (min-width: 768px) {
.container { .container {
max-width: 28rem; max-width: 18rem;
}
.hd {
margin-bottom: 1.5rem;
font-size: 1.125rem;
font-weight: 500;
}
.block {
margin-bottom: 1rem;
} }
} }
...@@ -3,6 +3,7 @@ import { Seat } from "../Seat/Seat.jsx"; ...@@ -3,6 +3,7 @@ import { Seat } from "../Seat/Seat.jsx";
import styles from "./Styles.module.css"; import styles from "./Styles.module.css";
import { toast, ToastContainer } from "react-toastify"; import { toast, ToastContainer } from "react-toastify";
import { Button } from "../../Form/Button/Button.jsx"; import { Button } from "../../Form/Button/Button.jsx";
export const SeatSelectionComponent = ({ export const SeatSelectionComponent = ({
reservedSeats = [], reservedSeats = [],
selectedSeats = [], selectedSeats = [],
...@@ -26,7 +27,8 @@ export const SeatSelectionComponent = ({ ...@@ -26,7 +27,8 @@ export const SeatSelectionComponent = ({
} else if (selectedseats.includes(seat)) { } else if (selectedseats.includes(seat)) {
setSelectedSeats(selectedseats.filter((e) => e !== seat)); setSelectedSeats(selectedseats.filter((e) => e !== seat));
} else { } else {
toast.info(`You can't select more than ${seatLimit} seat(s).`); window.location.href.startsWith("http://192.168.1.64:5173/") &&
toast.info(`You can't select more than ${seatLimit} seat(s).`);
} }
}; };
...@@ -35,14 +37,11 @@ export const SeatSelectionComponent = ({ ...@@ -35,14 +37,11 @@ export const SeatSelectionComponent = ({
if (selectedseats.length < seatLimit) { if (selectedseats.length < seatLimit) {
toast.error(`Please select atleast ${seatLimit} seat(s).`); toast.error(`Please select atleast ${seatLimit} seat(s).`);
} else { } else {
console.log("Triggered onChange with:", { seats: selectedseats });
onClick({ onClick({
seats: selectedseats, seats: selectedseats,
clearSelection: () => setSelectedSeats([]),
}); });
} }
}; };
const isSeatDisabled = (seat) => const isSeatDisabled = (seat) =>
reservedSeats.includes(seat) && !selectedSeats.includes(seat); reservedSeats.includes(seat) && !selectedSeats.includes(seat);
...@@ -90,7 +89,6 @@ export const SeatSelectionComponent = ({ ...@@ -90,7 +89,6 @@ export const SeatSelectionComponent = ({
</div> </div>
); );
}; };
SeatSelectionComponent.defaultProps = { SeatSelectionComponent.defaultProps = {
seats: [], seats: [],
reservedSeats: [], reservedSeats: [],
......
...@@ -23,23 +23,6 @@ ...@@ -23,23 +23,6 @@
gap: 1px; gap: 1px;
} }
.seat::before {
content: attr(data-tooltip);
position: relative;
bottom: 120%;
left: 50%;
transform: translateX(-50%);
color: #fff;
padding: 3px 6px;
font-size: 12px;
white-space: nowrap;
border-radius: 4px;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease-in-out;
z-index: 10;
}
.seat:hover::before { .seat:hover::before {
opacity: 1; opacity: 1;
} }
...@@ -61,13 +44,22 @@ ...@@ -61,13 +44,22 @@
.remove { .remove {
visibility: hidden; visibility: hidden;
} }
.btn {
margin-top: 2rem;
}
.btn button { .btn button {
display: flex; max-width: 35%;
justify-content: center;
border-radius: 1rem;
max-width: 45%;
margin: 0 auto; margin: 0 auto;
border-radius: 0.9rem;
margin-top: 2rem;
}
@media (min-width: 768px) {
.btn {
margin-top: 2rem;
}
.btn button {
display: flex;
justify-content: center;
border-radius: 1rem;
max-width: 45%;
margin: 0 auto;
}
} }
...@@ -16,8 +16,6 @@ export function ContextProvider({ children }) { ...@@ -16,8 +16,6 @@ export function ContextProvider({ children }) {
); );
const navigate = useNavigate(); const navigate = useNavigate();
console.log(reservedSeats);
const loginUser = async ({ mobile }) => { const loginUser = async ({ mobile }) => {
try { try {
const user = await api.loginUser(mobile); const user = await api.loginUser(mobile);
...@@ -143,8 +141,6 @@ export function ContextProvider({ children }) { ...@@ -143,8 +141,6 @@ export function ContextProvider({ children }) {
} }
getAllReservedSeats(); getAllReservedSeats();
}, []); }, []);
console.log("state reserved", reservedSeats);
console.log("Selected Seats:", reservedSeats.length);
const value = { const value = {
userSeats, userSeats,
......
...@@ -3,18 +3,36 @@ import { useAppContext } from "../context/Index"; ...@@ -3,18 +3,36 @@ import { useAppContext } from "../context/Index";
import { Login } from "../components/Forms/Login/Login"; import { Login } from "../components/Forms/Login/Login";
import { Sign } from "../components/Forms/SignUp/Sign"; import { Sign } from "../components/Forms/SignUp/Sign";
import styles from "./Styles.module.css"; import styles from "./Styles.module.css";
import { useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { toast, ToastContainer } from "react-toastify";
export const LoginPage = () => { export const LoginPage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation();
const { loginUser, registerUser } = useAppContext(); const { loginUser, registerUser } = useAppContext();
const [showLogin, setShowLogin] = useState(true); const [showLogin, setShowLogin] = useState(true);
useEffect(() => { useEffect(() => {
sessionStorage.clear(); sessionStorage.clear();
}, []); if (location.pathname === "/signup") {
setShowLogin(false);
}
}, [location.pathname]);
const handlelogin = async ({ mobile }) => { const handlelogin = async ({ mobile }) => {
if (!mobile) {
toast.error("please Enter Your Number");
return;
}
if (mobile.length < 10) {
toast.error("Mobile number is less than 10");
return;
}
if (!/^[6-9]\d{9}$/.test(mobile)) {
toast.info("Invalid Number");
return;
}
const res = await loginUser({ mobile }); const res = await loginUser({ mobile });
if (res) { if (res) {
navigate("/seat-limit"); navigate("/seat-limit");
...@@ -22,18 +40,49 @@ export const LoginPage = () => { ...@@ -22,18 +40,49 @@ export const LoginPage = () => {
}; };
const handleSignup = async ({ name, mobile }) => { const handleSignup = async ({ name, mobile }) => {
if (!name || !mobile) {
toast.error("Please enter both name and number");
return;
}
if (!/^[6-9]\d{9}$/.test(mobile)) {
toast.info("Please enter a valid 10-digit number");
return;
}
const confirmSeat = window.confirm("Are you sure,you want to signUp?");
if (!confirmSeat) return;
const res = await registerUser({ name, mobile }); const res = await registerUser({ name, mobile });
console.log("registered", res); console.log("registered", res);
setShowLogin(true); setShowLogin(true);
}; };
return ( return (
<div className={styles.login}> <>
{showLogin ? ( <div className={styles.login}>
<Login onClick={handlelogin} onSwitch={() => setShowLogin(false)} /> {showLogin ? (
) : ( <Login
<Sign onClick={handleSignup} onSwitch={() => setShowLogin(true)} /> onSubmit={handlelogin}
)} onSwitch={() => setShowLogin(false)}
</div> markdown={`Don't have an account? [SignUp](/signup)`}
labels={{
mobilePlaceholder: "Enter Your Number",
submitBtnText: "Submit",
mobileError: "Enter 10 digits",
}}
/>
) : (
<Sign
onSubmit={handleSignup}
onSwitch={() => setShowLogin(true)}
labels={{
mobileplaceholder: "Enter Your Number",
nameplaceholder: "Enter Your Name",
btnLabel: "Submit",
titleLabel: "SignUp",
}}
/>
)}
</div>
<ToastContainer />
</>
); );
}; };
...@@ -4,6 +4,7 @@ import { ...@@ -4,6 +4,7 @@ import {
getSeatLayout, getSeatLayout,
getReservedSeats, getReservedSeats,
getUserReservedSeats, getUserReservedSeats,
getReservedSeatOnly,
saveSeat, saveSeat,
updateSeat, updateSeat,
} from "../Api/Api"; } from "../Api/Api";
...@@ -36,11 +37,13 @@ function SeatBooking() { ...@@ -36,11 +37,13 @@ function SeatBooking() {
setLoading(true); setLoading(true);
setError(null); setError(null);
const [layoutData, allReserved, userRecord] = await Promise.all([ const [layoutData, allReserved, userRecord, reservedOnly] =
getSeatLayout(), await Promise.all([
getReservedSeats(), getSeatLayout(),
userId ? getUserReservedSeats(userId) : Promise.resolve(null), getReservedSeats(),
]); userId ? getUserReservedSeats(userId) : Promise.resolve(null),
getReservedSeatOnly(),
]);
if (isMounted) { if (isMounted) {
setSeatLayout(layoutData); setSeatLayout(layoutData);
......
import React from "react";
import Counter from "../components/Top-level/Counter/Counter"; import Counter from "../components/Top-level/Counter/Counter";
import { useAppContext } from "../context/Index"; import { useAppContext } from "../context/Index";
import styles from "./Styles.module.css"; import styles from "./Styles.module.css";
import { MdEventSeat } from "react-icons/md"; import { MdEventSeat } from "react-icons/md";
import { Header } from "../components/Layout/Card/Header"; import { Header } from "../components/Layout/Card/Header";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
export const SeatLimit = () => { export const SeatLimit = () => {
const navigate = useNavigate();
const totalSeats = 60; const totalSeats = 60;
const { reservedSeats } = useAppContext(); const { reservedSeats, getAllReservedSeats } = useAppContext();
const Seat = totalSeats - reservedSeats.length; const Seat = totalSeats - reservedSeats.length;
useEffect(() => {
const Timer = setInterval(() => {
getAllReservedSeats();
}, 500);
return () => clearTimeout(Timer);
}, [getAllReservedSeats]);
const handleSeat = (seatCount) => { const handleSeat = (seatCount) => {
console.log("handleSeat called with seatCount:", seatCount);
sessionStorage.setItem("seatLimit", seatCount); sessionStorage.setItem("seatLimit", seatCount);
window.location.replace("/booking"); navigate("/booking");
}; };
return ( return (
<> <>
<div className={styles.seat}> <div className={styles.seatContainer}>
<MdEventSeat className={styles.icon} /> <div className={styles.seat}>
<Header <MdEventSeat className={styles.icon} />
title={`Remaining Seats Available:${Seat}`} <Header
Color="#fff" title={`Remaining Seats Available:${Seat}`}
className={styles.line} Color="#fff"
/> className={styles.line}
/>
</div>
<Counter onSubmit={handleSeat} />
</div> </div>
<Counter onSubmit={handleSeat} />
</> </>
); );
}; };
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
justify-content: center; justify-content: center;
text-align: center; text-align: center;
margin-top: 0; margin-top: 0;
margin-bottom: 1.2rem; font-size: 0.8rem;
} }
.container { .container {
display: flex; display: flex;
...@@ -14,9 +14,6 @@ ...@@ -14,9 +14,6 @@
align-items: center; align-items: center;
} }
.login {
min-height: 20rem;
}
.logout { .logout {
display: flex; display: flex;
justify-content: end; justify-content: end;
...@@ -29,6 +26,8 @@ ...@@ -29,6 +26,8 @@
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size: 0.8rem;
margin-bottom: 1rem;
} }
.screen { .screen {
display: flex; display: flex;
...@@ -37,28 +36,35 @@ ...@@ -37,28 +36,35 @@
position: relative; position: relative;
min-width: 20rem; min-width: 20rem;
} }
.line { .line h2 {
font-size: 1rem; font-size: 15px;
color: #c7d2fe; color: #c7d2fe;
font-weight: 300; font-weight: 100;
margin-bottom: 1rem; margin-bottom: 1rem;
display: flex;
justify-content: center;
margin-left: 2.9rem;
flex-wrap: wrap;
} }
.line p { .seat {
text-align: center; margin-left: 2.3rem;
} }
.icon { .icon {
color: #fff; color: #fff;
position: absolute; position: absolute;
margin-left: 0; margin-left: -1.2rem;
margin-top: 1rem; margin-top: 0.2rem;
height: 2rem; height: 1rem;
width: 2rem; width: 1rem;
}
.seatContainer {
display: flex;
flex-direction: column;
box-sizing: border-box;
width: 100%;
max-width: 18rem;
justify-content: center;
align-items: center;
}
.login {
max-width: 20rem;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.container { .container {
display: flex; display: flex;
...@@ -70,16 +76,27 @@ ...@@ -70,16 +76,27 @@
width: 550; width: 550;
height: 210; height: 210;
} }
.login {
min-width: 40rem;
}
.icon { .icon {
margin-left: 0.5rem; margin-left: 0.5rem;
margin-top: 0.3rem; margin-top: 0.3rem;
height: 1.5rem; height: 1.5rem;
width: 1.5rem; width: 1.5rem;
} }
.line { .line h2 {
margin-left: 2.5rem; margin-left: 2.5rem;
width: unset;
font-size: 1.5rem;
font-weight: 300;
}
.footer {
font-size: 1.2rem;
}
.head {
font-size: 1.5rem;
margin-top: 1rem;
}
.seat {
margin-left: 2rem;
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment