Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
training-seat-booking
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Manivasagam S
training-seat-booking
Commits
7260cb25
Commit
7260cb25
authored
Jun 19, 2025
by
Manivasagam S
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code changes
parent
d47e22b7
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
222 additions
and
265 deletions
+222
-265
Auth.jsx
src/Components/Auth/Auth.jsx
+0
-1
Auth.stories.jsx
src/Components/Auth/Auth.stories.jsx
+0
-2
Button.module.css
src/Components/Base/Buttons/Button.module.css
+1
-2
Modal.module.css
src/Components/Base/Modal/Modal.module.css
+2
-2
Select.jsx
src/Components/Base/Select/Select.jsx
+4
-2
Select.module.css
src/Components/Base/Select/Select.module.css
+6
-3
Select.stories.jsx
src/Components/Base/Select/Select.stories.jsx
+31
-23
Login.jsx
src/Components/Form/Login/Login.jsx
+0
-1
Login.module.css
src/Components/Form/Login/Login.module.css
+0
-1
SeatSelectForm.module.css
src/Components/Form/SeatSelectForm/SeatSelectForm.module.css
+1
-1
SignUp.jsx
src/Components/Form/SignUp/SignUp.jsx
+0
-9
SignUp.module.css
src/Components/Form/SignUp/SignUp.module.css
+3
-3
Screen.module.css
src/Components/Shared/Screen/Screen.module.css
+3
-3
Notification.module.css
...Components/Top-level/Notification/Notification.module.css
+2
-2
Seat.jsx
src/Components/Top-level/Seat/Seat.jsx
+4
-4
Seat.module.css
src/Components/Top-level/Seat/Seat.module.css
+2
-5
SeatLayout.jsx
src/Components/Top-level/SeatLayout/SeatLayout.jsx
+23
-55
SeatLayout.stories.jsx
src/Components/Top-level/SeatLayout/SeatLayout.stories.jsx
+9
-58
Selectseat.jsx
src/Components/Top-level/Seatselect/Selectseat.jsx
+66
-56
AuthPage.jsx
src/Pages/AuthPage.jsx
+24
-23
db.json
src/db.json
+41
-9
No files found.
src/Components/Auth/Auth.jsx
View file @
7260cb25
...
...
@@ -13,7 +13,6 @@ export const Auth = ({
loginTabLabel
=
"Login"
,
signupTabLabel
=
"Signup"
,
initialMode
=
"login"
,
showForgotPassword
=
true
,
showSwitchPrompt
=
true
,
})
=>
{
const
[
isLoginMode
,
setIsLoginMode
]
=
useState
(
initialMode
===
"login"
);
...
...
src/Components/Auth/Auth.stories.jsx
View file @
7260cb25
...
...
@@ -16,7 +16,6 @@ export default {
options
:
[
"login"
,
"signup"
],
name
:
"Initial Mode"
,
},
showForgotPassword
:
{
control
:
"boolean"
,
name
:
"Show Forgot Password"
},
showSwitchPrompt
:
{
control
:
"boolean"
,
name
:
"Show Switch Prompt"
},
},
parameters
:
{
...
...
@@ -60,6 +59,5 @@ ModeSwitcher.args = {
loginTabLabel
:
"Login"
,
signupTabLabel
:
"Signup"
,
initialMode
:
"login"
,
showForgotPassword
:
true
,
showSwitchPrompt
:
true
,
};
src/Components/Base/Buttons/Button.module.css
View file @
7260cb25
...
...
@@ -29,7 +29,6 @@
}
.primary
:disabled
{
opacity
:
0.5
;
cursor
:
not-allowed
;
opacity
:
0.7
;
...
...
@@ -48,7 +47,7 @@
}
.secondary
:disabled
{
background-color
:
#979595
;
opacity
:
0.7
;
cursor
:
not-allowed
;
}
...
...
src/Components/Base/Modal/Modal.module.css
View file @
7260cb25
...
...
@@ -40,7 +40,7 @@
gap
:
1rem
;
}
/*
.modalselect {
padding: 10px;
border: 1px solid #d1d5db;
...
...
@@ -57,4 +57,4 @@
}
*/
src/Components/Base/Select/Select.jsx
View file @
7260cb25
import
styles
from
'@/Components/Base/Select/Select.module.css'
;
export
const
Select
=
({
label
,
options
,
value
,
onChange
})
=>
{
export
const
Select
=
({
label
,
options
,
value
,
onChange
,
errorMessage
})
=>
{
return
(
<
div
className=
{
styles
.
container
}
>
{
label
&&
<
label
className=
{
styles
.
label
}
>
{
label
}
</
label
>
}
<
select
className=
{
styles
.
select
}
value=
{
value
}
onChange=
{
onChange
}
>
<
select
className=
{
`${styles.select} ${errorMessage ? styles.errorSelect : ''}`
}
value=
{
value
}
onChange=
{
onChange
}
>
{
(
options
||
[]).
map
((
opt
,
index
)
=>
(
<
option
key=
{
index
}
value=
{
opt
.
value
}
className=
{
styles
.
option
}
>
{
opt
.
label
}
</
option
>
))
}
</
select
>
{
errorMessage
&&
<
p
className=
{
styles
.
errorMessage
}
>
{
errorMessage
}
</
p
>
}
</
div
>
);
};
src/Components/Base/Select/Select.module.css
View file @
7260cb25
...
...
@@ -7,9 +7,7 @@
.label
{
font-weight
:
bold
;
}
.select
:focus
{
outline-color
:
var
(
--primary
);
}
.select
{
padding
:
0.6rem
;
font-size
:
1em
;
...
...
@@ -26,3 +24,7 @@
border-radius
:
4px
;
}
.errorMessage
{
color
:
red
;
margin-left
:
3px
;
}
\ No newline at end of file
src/Components/Base/Select/Select.stories.jsx
View file @
7260cb25
...
...
@@ -6,30 +6,38 @@ export default {
component
:
Select
,
argTypes
:
{
label
:
{
control
:
'text'
},
onChange
:
{
action
:
'onChange'
},
onChange
:
{
action
:
'onChange'
},
},
};
export
const
Default
=
(
args
)
=>
{
const
options
=
[
{
value
:
'1'
,
label
:
'1 seat'
},
{
value
:
'2'
,
label
:
'2 seats'
},
{
value
:
'3'
,
label
:
'3 seats'
},
];
return
(
<
Select
{
...
args
}
options=
{
options
}
onChange=
{
(
e
)
=>
{
args
.
onChange
(
e
);
}
}
/>
);
};
Default
.
args
=
{
label
:
'Choose a seat'
,
};
const
options
=
[
{
value
:
''
,
label
:
'Select seat'
},
{
value
:
'1'
,
label
:
'1 seat'
},
{
value
:
'2'
,
label
:
'2 seats'
},
{
value
:
'3'
,
label
:
'3 seats'
},
];
export
const
ValidandInvalid
=
(
args
)
=>
(
<
div
>
<
div
>
<
Select
{
...
args
}
label=
"Select without error"
value=
"1"
options=
{
options
}
errorMessage=
""
onChange=
{
(
e
)
=>
args
.
onChange
(
e
)
}
/>
</
div
>
<
div
>
<
Select
{
...
args
}
label=
"Select with error"
value=
""
options=
{
options
}
errorMessage=
"Please select a seat."
onChange=
{
(
e
)
=>
args
.
onChange
(
e
)
}
/>
</
div
>
</
div
>
);
src/Components/Form/Login/Login.jsx
View file @
7260cb25
...
...
@@ -4,7 +4,6 @@ import { Button } from "@/Components//Base/Buttons/Button";
import
styles
from
"@/Components/Form/Login/Login.module.css"
;
export
const
Login
=
({
loginHeading
=
"Login With Your Mobile Number"
,
placeholder
=
"Enter Mobile Number"
,
onLogin
,
})
=>
{
...
...
src/Components/Form/Login/Login.module.css
View file @
7260cb25
...
...
@@ -4,7 +4,6 @@
}
.headerNew
{
font-size
:
1.7em
;
font-family
:
'Segoe UI'
;
color
:
black
;
margin-bottom
:
1.5rem
;
text-align
:
center
;
...
...
src/Components/Form/SeatSelectForm/SeatSelectForm.module.css
View file @
7260cb25
...
...
@@ -2,7 +2,7 @@
.modalform
{
display
:
flex
;
flex-direction
:
column
;
gap
:
1
6px
;
gap
:
1
rem
;
min-width
:
auto
;
}
...
...
src/Components/Form/SignUp/SignUp.jsx
View file @
7260cb25
...
...
@@ -59,15 +59,6 @@ export const SignUp = ({
if
(
!
validateForm
())
return
;
try
{
const
res
=
await
getUserByPhone
(
formData
.
phoneNumber
);
if
(
res
.
data
.
length
>
0
)
{
setErrors
((
prev
)
=>
({
...
prev
,
phoneNumber
:
'Phone number already registered'
,
}));
return
;
}
await
onSignUpSubmit
?.(
formData
);
setFormData
({
name
:
''
,
email
:
''
,
phoneNumber
:
''
});
}
catch
(
error
)
{
...
...
src/Components/Form/SignUp/SignUp.module.css
View file @
7260cb25
...
...
@@ -13,12 +13,12 @@
border-radius
:
2rem
;
}
.text
{
/*
.text {
margin-bottom: 2rem;
color: #00020c;
font-family
:
'Segoe UI'
;
/* font-family: 'Segoe UI';} */
}
.form
{
display
:
flex
;
flex-direction
:
column
;
...
...
src/Components/Shared/Screen/Screen.module.css
View file @
7260cb25
...
...
@@ -3,12 +3,12 @@
justify-content
:
center
;
align-items
:
center
;
width
:
100%
;
min-width
:
30
rem
;
min-width
:
15
rem
;
position
:
relative
;
bottom
:
1rem
;
}
@media
(
min-width
:
32
0px
){
@media
(
min-width
:
64
0px
){
.shadow
{
min-width
:
15
rem
;
min-width
:
30
rem
;
}
}
src/Components/Top-level/Notification/Notification.module.css
View file @
7260cb25
...
...
@@ -32,7 +32,7 @@
.title
,
.msg
{
color
:
#100f0f
;
color
:
black
;
font-weight
:
bold
;
}
...
...
@@ -119,7 +119,7 @@
.seatListWrapper
{
margin-top
:
1rem
;
background-color
:
#f5f5f5
;
background-color
:
white
;
padding
:
1rem
;
border-radius
:
1rem
;
box-shadow
:
0
1px
4px
rgba
(
0
,
0
,
0
,
0.1
);
...
...
src/Components/Top-level/Seat/Seat.jsx
View file @
7260cb25
...
...
@@ -3,15 +3,15 @@ import cn from 'classnames';
import
styles
from
'@/Components/Top-level/Seat/Seat.module.css'
;
export
const
Seat
=
({
seatNo
,
status
,
onClick
})
=>
{
const
isMine
=
status
===
'
mine'
||
status
===
'mine-
unselected'
;
const
isMine
=
status
===
'
selected'
||
status
===
'
unselected'
;
const
className
=
cn
(
styles
.
seat
,
{
[
styles
.
noSeat
]:
status
===
'none'
,
[
styles
.
available
]:
status
===
'available'
,
[
styles
.
reserved
]:
status
===
'reserved'
,
[
styles
.
selected
]:
status
===
'selected'
,
[
styles
.
mine
]:
isMine
,
[
styles
.
unselected
]:
status
===
'
mine-
unselected'
,
[
styles
.
selected
]:
isMine
,
[
styles
.
unselected
]:
status
===
'unselected'
,
});
return
(
...
...
@@ -19,7 +19,7 @@ export const Seat = ({ seatNo, status, onClick }) => {
className=
{
className
}
data
-
tooltip=
{
seatNo
}
role=
"button"
tabIndex=
{
[
'available'
,
'selected'
,
'mine'
,
'mine-
unselected'
].
includes
(
status
)
?
0
:
-
1
}
tabIndex=
{
[
'available'
,
'selected'
,
"reserved"
,
'
unselected'
].
includes
(
status
)
?
0
:
-
1
}
onClick=
{
onClick
}
>
{
null
}
...
...
src/Components/Top-level/Seat/Seat.module.css
View file @
7260cb25
...
...
@@ -25,10 +25,7 @@
.reserved
{
background-color
:
var
(
--reserved
);
}
.mine
{
background-color
:
var
(
--selected
);
cursor
:
pointer
;
}
.unselected
{
background-color
:
transparent
;
border
:
0.5px
solid
rgba
(
164
,
175
,
255
,
1
);
...
...
@@ -67,7 +64,7 @@
width
:
3.75rem
;
border-radius
:
3px
;
background-color
:
#f7f4f4
;
color
:
#080808
;
color
:
black
;
content
:
attr
(
data-tooltip
);
text-align
:
center
;
font-size
:
0.75rem
;
...
...
src/Components/Top-level/SeatLayout/SeatLayout.jsx
View file @
7260cb25
import
{
useState
,
useEffect
}
from
'react'
;
import
PropTypes
from
'prop-types'
;
import
{
useState
,
useEffect
}
from
'react'
;
import
{
Seat
}
from
'@/Components/Top-level/Seat/Seat.jsx'
;
import
styles
from
'@/Components/Top-level/SeatLayout/SeatLayout.module.css'
;
import
{
seatsData
}
from
'@/Components/Top-level/SeatLayout/SeatsData.js'
;
import
{
toast
}
from
'react-toastify'
;
const
populateSeatsArray
=
(
selectedSeats
,
reservedSeats
,
currentReservedSeats
)
=>
{
const
populateSeatsArray
=
(
selectedSeats
,
reservedSeats
)
=>
{
return
seatsData
.
map
(({
row
,
seats
})
=>
seats
.
map
((
number
)
=>
{
const
seatNo
=
row
+
number
;
if
(
number
===
'/'
)
return
{
seatNo
,
status
:
'none'
};
const
isMine
=
currentReservedSeats
.
includes
(
seatNo
);
const
isSelected
=
selectedSeats
.
includes
(
seatNo
);
const
isReserved
=
reservedSeats
.
includes
(
seatNo
);
if
(
isMine
&&
isSelected
)
return
{
seatNo
,
status
:
'selected'
};
if
(
isMine
&&
!
isSelected
)
return
{
seatNo
,
status
:
'mine-unselected'
};
if
(
isReserved
)
return
{
seatNo
,
status
:
'reserved'
};
if
(
isSelected
)
return
{
seatNo
,
status
:
'selected'
};
if
(
reservedSeats
.
includes
(
seatNo
))
return
{
seatNo
,
status
:
'reserved'
};
if
(
selectedSeats
.
includes
(
seatNo
))
return
{
seatNo
,
status
:
'selected'
};
return
{
seatNo
,
status
:
'available'
};
})
);
...
...
@@ -26,58 +19,34 @@ const populateSeatsArray = (selectedSeats, reservedSeats, currentReservedSeats)
export
const
SeatLayout
=
({
selectedSeats
:
initialSelected
=
[],
reservedSeats
=
[],
currentReservedSeats
=
[],
reservedSeats
,
limit
,
onSelectionChange
,
})
=>
{
const
[
localSelectedSeats
,
setLocalSelectedSeats
]
=
useState
(
currentReservedSeats
);
const
[
selectedSeats
,
setSelectedSeats
]
=
useState
(
initialSelected
);
useEffect
(()
=>
{
setLocalSelectedSeats
(
currentReservedSeats
);
},
[
currentReservedSeats
]);
useEffect
(()
=>
{
onSelectionChange
?.(
localSelectedSeats
);
},
[
localSelectedSeats
]);
const
seatClickHandler
=
(
seat
)
=>
{
const
{
seatNo
,
status
}
=
seat
;
const
isMine
=
currentReservedSeats
.
includes
(
seatNo
);
const
isSelected
=
localSelectedSeats
.
includes
(
seatNo
);
setSelectedSeats
(
initialSelected
);
},
[
initialSelected
]);
const
seatClickHandler
=
({
seatNo
,
status
})
=>
{
if
(
status
===
'reserved'
)
return
;
setLocalSelectedSeats
((
prev
)
=>
{
const
updated
=
[...
prev
];
const
isSelected
=
selectedSeats
.
includes
(
seatNo
);
const
updated
=
isSelected
?
selectedSeats
.
filter
((
s
)
=>
s
!==
seatNo
)
:
[...
selectedSeats
,
seatNo
];
if
(
isSelected
)
{
return
updated
.
filter
((
s
)
=>
s
!==
seatNo
);
// unselect
}
else
{
const
newlySelected
=
updated
.
filter
(
(
s
)
=>
!
currentReservedSeats
.
includes
(
s
)
);
const
unselectedMine
=
currentReservedSeats
.
filter
(
(
s
)
=>
!
updated
.
includes
(
s
)
);
if
(
!
isSelected
&&
updated
.
length
>
limit
)
{
toast
.
warn
(
`Only
${
limit
}
seat
${
limit
>
1
?
's'
:
''
}
allowed`
);
return
;
}
const
totalAllowed
=
limit
+
unselectedMine
.
length
;
if
(
newlySelected
.
length
<
totalAllowed
)
{
return
[...
updated
,
seatNo
];
}
else
{
return
updated
;
}
}
});
setSelectedSeats
(
updated
);
onSelectionChange
(
updated
);
// fire callback
};
const
renderedSeats
=
populateSeatsArray
(
localSelectedSeats
,
reservedSeats
,
currentReservedSeats
);
const
renderedSeats
=
populateSeatsArray
(
selectedSeats
,
reservedSeats
);
return
(
<
div
className=
{
styles
.
container
}
>
...
...
@@ -94,8 +63,7 @@ export const SeatLayout = ({
SeatLayout
.
propTypes
=
{
selectedSeats
:
PropTypes
.
arrayOf
(
PropTypes
.
string
),
reservedSeats
:
PropTypes
.
arrayOf
(
PropTypes
.
string
),
currentReservedSeats
:
PropTypes
.
arrayOf
(
PropTypes
.
string
),
reservedSeats
:
PropTypes
.
arrayOf
(
PropTypes
.
string
).
isRequired
,
limit
:
PropTypes
.
number
.
isRequired
,
onSelectionChange
:
PropTypes
.
func
.
isRequired
,
onSelectionChange
:
PropTypes
.
func
,
};
src/Components/Top-level/SeatLayout/SeatLayout.stories.jsx
View file @
7260cb25
import
{
SeatLayout
}
from
'@/Components/Top-level/SeatLayout/SeatLayout'
;
import
{
action
}
from
'@storybook/addon-actions'
;
const
reservedSeatsSample
=
[
'A1'
,
'B2'
,
'C3'
];
const
currentUserReservedSeats
=
[
'A3'
,
'B4'
];
const
logSelectionChange
=
action
(
'Clicked/Unclicked'
);
export
default
{
title
:
'Toplevel/SeatLayout'
,
component
:
SeatLayout
,
...
...
@@ -15,63 +11,18 @@ export default {
layout
:
'centered'
,
},
argTypes
:
{
selectedSeats
:
{
control
:
{
type
:
'array'
},
description
:
'Seats currently selected by the user'
,
},
reservedSeats
:
{
control
:
{
type
:
'array'
},
description
:
'Seats reserved by others'
,
},
currentReservedSeats
:
{
control
:
{
type
:
'array'
},
description
:
'Seats reserved by the logged-in user'
,
},
selectedSeats
:
{
control
:
'array'
},
reservedSeats
:
{
control
:
'array'
},
limit
:
{
control
:
'number'
},
},
};
const
modeConfig
=
{
available
:
{
selectedSeats
:
[],
reservedSeats
:
[],
currentReservedSeats
:
[],
limit
:
3
,
},
reserved
:
{
selectedSeats
:
[],
reservedSeats
:
reservedSeatsSample
,
currentReservedSeats
:
[],
limit
:
2
,
},
selected
:
{
selectedSeats
:
[],
reservedSeats
:
[],
currentReservedSeats
:
currentUserReservedSeats
,
limit
:
1
,
},
};
export
const
Default
=
(
args
)
=>
{
const
config
=
modeConfig
[
args
.
mode
]
||
modeConfig
.
available
;
return
(
<
SeatLayout
selectedSeats=
{
args
.
selectedSeats
.
length
?
args
.
selectedSeats
:
config
.
selectedSeats
}
reservedSeats=
{
args
.
reservedSeats
.
length
?
args
.
reservedSeats
:
config
.
reservedSeats
}
currentReservedSeats=
{
args
.
currentReservedSeats
.
length
?
args
.
currentReservedSeats
:
config
.
currentReservedSeats
}
limit=
{
config
.
limit
}
onSelectionChange=
{
logSelectionChange
}
/>
);
};
export
const
Default
=
(
args
)
=>
(
<
SeatLayout
{
...
args
}
onSelectionChange=
{
action
(
'Clicked/Unclicked'
)
}
/>
);
Default
.
args
=
{
mode
:
'available'
,
selectedSeats
:
[],
reservedSeats
:
[],
currentReservedSeats
:
[],
selectedSeats
:
[
'B1'
],
reservedSeats
:
[
'A1'
,
'B2'
],
limit
:
3
,
};
src/Components/Top-level/Seatselect/Selectseat.jsx
View file @
7260cb25
...
...
@@ -14,8 +14,8 @@ import { AiOutlineLogout } from "react-icons/ai";
export
const
Selectseat
=
({
onLogout
})
=>
{
const
[
selectedSeats
,
setSelectedSeats
]
=
useState
([]);
const
[
selectedData
,
setselectedData
]
=
useState
([]);
const
[
reservedSeats
,
setreserved
Seats
]
=
useState
([]);
const
[
reservedSeats
,
setReservedSeats
]
=
useState
([]);
const
[
userSeats
,
setUser
Seats
]
=
useState
([]);
const
[
seatCount
,
setSeatCount
]
=
useState
(
1
);
const
[
availableSeats
,
setAvailableSeats
]
=
useState
(
0
);
const
[
showSelect
,
setShowSelect
]
=
useState
(
true
);
...
...
@@ -24,31 +24,33 @@ export const Selectseat = ({ onLogout }) => {
useEffect
(()
=>
{
getAllUsers
()
.
then
(
res
=>
{
.
then
(
(
res
)
=>
{
const
users
=
res
.
data
;
const
totalSeats
=
60
;
const
loggedUser
=
getCurrentUser
();
const
totalSeats
=
60
;
const
allReserved
=
users
.
flatMap
(
u
=>
u
.
reservedSeats
||
[]);
const
currentUser
=
users
.
find
(
u
=>
u
.
phoneNumber
===
loggedUser
.
phoneNumber
);
const
userSeats
=
currentUser
?.
reservedSeats
||
[];
const
othersReserved
=
allReserved
.
filter
(
seat
=>
!
userSeats
.
includes
(
seat
));
setselectedData
(
userSeats
);
setreservedSeats
(
othersReserved
);
setSeatCount
(
userSeats
.
length
);
const
currentUser
=
users
.
find
(
(
u
)
=>
u
.
phoneNumber
===
loggedUser
.
phoneNumber
);
const
userReserved
=
currentUser
?.
reservedSeats
||
[];
const
allReserved
=
users
.
flatMap
((
u
)
=>
u
.
reservedSeats
||
[]);
const
othersReserved
=
allReserved
.
filter
(
(
seat
)
=>
!
userReserved
.
includes
(
seat
)
);
setUserSeats
(
userReserved
);
setSelectedSeats
(
userReserved
);
setReservedSeats
(
othersReserved
);
setSeatCount
(
userReserved
.
length
);
setAvailableSeats
(
totalSeats
-
allReserved
.
length
);
setShowSelect
(
true
);
const
available
=
totalSeats
-
allReserved
.
length
;
setAvailableSeats
(
available
);
if
(
currentUser
?.
name
&&
!
hasWelcomed
.
current
)
{
toast
.
success
(
`Welcome😊,
${
currentUser
.
name
}
`
);
toast
.
success
(
`Welcome
😊,
${
currentUser
.
name
}
`
);
hasWelcomed
.
current
=
true
;
}
})
.
catch
(
err
=>
{
.
catch
(
(
err
)
=>
{
console
.
error
(
"Error fetching users"
,
err
);
toast
.
error
(
"Failed to load seat data."
);
});
...
...
@@ -56,60 +58,72 @@ export const Selectseat = ({ onLogout }) => {
const
confirmHandler
=
()
=>
{
const
user
=
getCurrentUser
();
if
(
!
user
||
!
user
.
phoneNumber
?.
trim
())
{
toast
.
warn
(
"User not logged in"
);
return
;
}
const
unselectedReserved
=
selectedData
.
filter
(
seat
=>
!
selectedSeats
.
includes
(
seat
));
const
newlySelected
=
selectedSeats
.
filter
(
s
=>
!
selectedData
.
includes
(
s
));
console
.
log
(
"test"
,
unselectedReserved
);
if
(
unselectedReserved
.
length
>
0
&&
newlySelected
.
length
<
unselectedReserved
.
length
)
{
toast
.
error
(
`You unselected
${
unselectedReserved
.
length
}
reserved seat(s), so you must select
${
unselectedReserved
.
length
}
new seat(s).`
);
return
;
}
if
(
newlySelected
.
length
<
seatCount
-
selectedData
.
length
)
{
toast
.
error
(
`You must select exactly
${
seatCount
-
selectedData
.
length
}
new seats`
);
const
unselectedMine
=
userSeats
.
filter
(
(
seat
)
=>
!
selectedSeats
.
includes
(
seat
)
);
const
newlySelected
=
selectedSeats
.
filter
(
(
seat
)
=>
!
userSeats
.
includes
(
seat
)
);
if
(
unselectedMine
.
length
>
0
&&
newlySelected
.
length
<
unselectedMine
.
length
)
{
toast
.
error
(
`You unselected
${
unselectedMine
.
length
}
seat(s), select
${
unselectedMine
.
length
}
new.`
);
hasWelcomed
.
current
=
true
;
return
;
}
if
(
selectedSeats
.
length
!==
seatCount
)
{
toast
.
error
(
`You must select exactly
${
seatCount
}
seat(s).`
);
hasWelcomed
.
current
=
true
;
return
;
}
getAllUsers
()
.
then
(
res
=>
{
.
then
(
(
res
)
=>
{
const
users
=
res
.
data
;
const
currentUser
=
users
.
find
(
u
=>
u
.
phoneNumber
===
user
.
phoneNumber
);
const
currentUser
=
users
.
find
(
(
u
)
=>
u
.
phoneNumber
===
user
.
phoneNumber
);
if
(
!
currentUser
)
{
toast
.
error
(
"User not found"
);
return
;
}
const
latestReserved
=
users
.
flatMap
(
u
=>
u
.
reservedSeats
||
[])
.
filter
(
seat
=>
!
currentUser
.
reservedSeats
.
includes
(
seat
));
const
conflictSeats
=
selectedSeats
.
filter
(
seat
=>
latestReserved
.
includes
(
seat
));
const
latestOthersReserved
=
users
.
flatMap
((
u
)
=>
u
.
reservedSeats
||
[])
.
filter
((
seat
)
=>
!
currentUser
.
reservedSeats
.
includes
(
seat
));
if
(
conflictSeats
.
length
>
0
)
{
toast
.
error
(
`The following seats were just taken:
${
conflictSeats
.
join
(
", "
)}
`
);
hasWelcomed
.
current
=
true
;
const
conflict
=
selectedSeats
.
filter
((
seat
)
=>
latestOthersReserved
.
includes
(
seat
)
);
if
(
conflict
.
length
>
0
)
{
toast
.
error
(
`These seats were just taken:
${
conflict
.
join
(
", "
)}
`
);
return
;
}
return
updateUserReservedSeats
(
currentUser
.
id
,
selectedSeats
);
})
.
then
(
res
=>
{
.
then
(
(
res
)
=>
{
if
(
res
)
{
toast
.
success
(
"Seats booked!"
);
hasWelcomed
.
current
=
true
;
hasWelcomed
.
current
=
true
;
localStorage
.
setItem
(
"bookedSeats"
,
JSON
.
stringify
(
selectedSeats
));
setSelectedSeats
([]);
setTimeout
(()
=>
window
.
location
.
replace
(
"/success"
),
1000
);
}
})
.
catch
(
err
=>
{
.
catch
(
(
err
)
=>
{
console
.
error
(
"Error confirming seats"
,
err
);
toast
.
error
(
"Failed to confirm seats"
);
toast
.
error
(
"Failed to confirm seats
.
"
);
setTimeout
(()
=>
window
.
location
.
replace
(
"/error"
),
1000
);
});
};
...
...
@@ -117,8 +131,8 @@ export const Selectseat = ({ onLogout }) => {
const
handleModal
=
()
=>
setShowSelect
(
false
);
const
seatOptions
=
Array
.
from
({
length
:
availableSeats
}).
map
((
_
,
i
)
=>
({
value
:
selectedData
.
length
+
i
+
0
,
label
:
`
${
selectedData
.
length
+
i
+
0
}
seats`
value
:
userSeats
.
length
+
i
+
0
,
label
:
`
${
userSeats
.
length
+
i
+
0
}
seats`
,
}));
return
(
...
...
@@ -129,27 +143,23 @@ export const Selectseat = ({ onLogout }) => {
<
div
className=
{
styles
.
container
}
>
<
h2
className=
{
styles
.
text
}
>
Choose Seats
</
h2
>
<
Screen
/>
<
div
className=
{
styles
.
seatcontainer
}
>
<
SeatLayout
selectedSeats=
{
selectedSeats
}
reservedSeats=
{
reservedSeats
}
currentReservedSeats=
{
selectedData
}
limit=
{
seatCount
-
selectedData
.
length
}
limit=
{
seatCount
}
onSelectionChange=
{
setSelectedSeats
}
/>
</
div
>
<
div
className=
{
styles
.
button
}
>
<
Button
variant=
"secondary"
label=
"Confirm"
size=
"md"
onClick=
{
confirmHandler
}
disabled=
{
se
atCount
===
0
||
selectedSeats
.
length
<
seatCount
-
selectedData
.
length
}
disabled=
{
se
lectedSeats
.
length
!==
seatCount
}
/>
</
div
>
<
div
className=
{
styles
.
legend
}
>
<
Legend
/>
</
div
>
...
...
@@ -157,11 +167,11 @@ export const Selectseat = ({ onLogout }) => {
{
showSelect
&&
(
<
Modal
title=
{
selectedData
.
length
>
0
?
`You have already booked ${
selectedData.length} seat(s)
Add more?`
title=
{
userSeats
.
length
>
0
?
`You have already booked ${
userSeats.length} seat(s).
Add more?`
:
"Choose Number of Seats"
}
}
availableSeats=
{
availableSeats
}
seatCount=
{
seatCount
}
setSeatCount=
{
setSeatCount
}
...
...
src/Pages/AuthPage.jsx
View file @
7260cb25
...
...
@@ -22,33 +22,34 @@ export const AuthPage = () => {
}
};
const
handleSignUp
=
async
(
formData
)
=>
{
try
{
if
(
!
formData
||
!
formData
.
phoneNumber
)
{
toast
.
error
(
"Invalid form data"
);
return
;
}
const
response
=
await
getUserByPhone
(
formData
.
phoneNumber
);
if
(
response
.
data
.
length
>
0
)
{
toast
.
warn
(
"Phone number already registered."
);
return
;
}
const
handleSignUp
=
async
(
formData
)
=>
{
try
{
if
(
!
formData
||
!
formData
.
phoneNumber
)
{
toast
.
error
(
"📛 Invalid form data"
);
return
;
}
const
newUser
=
{
...
formData
,
reservedSeats
:
[]
};
const
postRes
=
await
postUser
(
newUser
);
// ✅ Check if phone number already exists
const
response
=
await
getUserByPhone
(
formData
.
phoneNumber
);
if
(
response
.
data
.
length
>
0
)
{
toast
.
warn
(
"📱 Phone number already registered."
);
return
;
}
const
newUser
=
{
...
formData
,
reservedSeats
:
[]
};
const
postRes
=
await
postUser
(
newUser
);
if
(
postRes
.
status
===
201
)
{
localStorage
.
setItem
(
"user"
,
JSON
.
stringify
(
postRes
.
data
));
toast
.
success
(
"Account created successfully!"
);
}
else
{
toast
.
error
(
"Failed to create account. Try again."
);
}
}
catch
(
error
)
{
console
.
error
(
"Sign up error:"
,
error
);
toast
.
error
(
"Network error or server not available."
);
if
(
postRes
.
status
===
201
)
{
localStorage
.
setItem
(
"user"
,
JSON
.
stringify
(
postRes
.
data
));
toast
.
success
(
"Account created successfully!"
);
}
else
{
toast
.
error
(
"Failed to create account. Try again."
);
}
};
}
catch
(
error
)
{
console
.
error
(
"Sign up error:"
,
error
);
toast
.
error
(
"🌐 Network error or server not available."
);
}
};
return
(
<
Auth
...
...
src/db.json
View file @
7260cb25
...
...
@@ -23,23 +23,33 @@
"F2"
,
"F1"
,
"F8"
,
"D8"
,
"E7"
,
"G2"
,
"B3"
,
"D6"
,
"G5"
,
"F5"
,
"F6"
,
"E6"
,
"D5"
,
"G6"
,
"E5"
,
"G7"
,
"A4"
,
"A5"
,
"A6"
,
"A3"
"B2"
,
"B3"
,
"D8"
,
"B1"
,
"H4"
,
"H5"
,
"C1"
,
"A3"
,
"A2"
,
"C2"
,
"G5"
,
"G6"
,
"G1"
,
"H3"
,
"H6"
,
"F3"
,
"E5"
,
"F6"
,
"B8"
]
},
{
...
...
@@ -189,6 +199,27 @@
"D3"
,
"C4"
]
},
{
"id"
:
"f58c"
,
"name"
:
"mani"
,
"email"
:
"kani@gmail.com"
,
"phoneNumber"
:
"1234567598"
,
"reservedSeats"
:
[]
},
{
"id"
:
"c905"
,
"name"
:
"mani"
,
"email"
:
"kani@gmail.com"
,
"phoneNumber"
:
"1234567894"
,
"reservedSeats"
:
[]
},
{
"id"
:
"c9d6"
,
"name"
:
"mani"
,
"email"
:
"mani@gmail.com"
,
"phoneNumber"
:
"2134567809"
,
"reservedSeats"
:
[]
}
]
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment