lolpee69 revised this gist . Go to revision
5 files changed, 298 insertions
Book(file created)
@@ -0,0 +1,120 @@ | |||
1 | + | import React, { Component } from 'react'; | |
2 | + | import { connect } from 'react-redux'; | |
3 | + | import { bookSlot, saveDetails, selectSlot } from '../Action/action'; | |
4 | + | import { withRouter } from './withRouter'; | |
5 | + | ||
6 | + | class Booking extends Component { | |
7 | + | constructor(props) { | |
8 | + | super(props); | |
9 | + | this.state = { | |
10 | + | selectedSlot: null, | |
11 | + | name: '', | |
12 | + | contact: '', | |
13 | + | errorStmt: '', | |
14 | + | }; | |
15 | + | } | |
16 | + | ||
17 | + | handleSlotClick = (slot) => { | |
18 | + | const { bookingCheck, selectedDate } = this.props; | |
19 | + | const isBooked = bookingCheck.some(b => b.slot === slot && b.date === selectedDate); | |
20 | + | if (!isBooked) { | |
21 | + | this.setState({ selectedSlot: slot, errorStmt: '' }); | |
22 | + | this.props.selectSlot(slot); | |
23 | + | } | |
24 | + | }; | |
25 | + | ||
26 | + | validate = () => { | |
27 | + | const { selectedSlot, name, contact } = this.state; | |
28 | + | if (!selectedSlot) { | |
29 | + | this.setState({ errorStmt: 'Select your slot!!!' }); | |
30 | + | return false; | |
31 | + | } | |
32 | + | const nameRegex = /^[A-Za-z ]+$/; | |
33 | + | const phoneRegex = /^[0-9]{10}$/; | |
34 | + | if (!nameRegex.test(name) || !phoneRegex.test(contact)) { | |
35 | + | this.setState({ errorStmt: 'Invalid Input!!!' }); | |
36 | + | return false; | |
37 | + | } | |
38 | + | return true; | |
39 | + | }; | |
40 | + | ||
41 | + | handleBook = () => { | |
42 | + | if (!this.validate()) return; | |
43 | + | const bookingID = Math.floor(1000 + Math.random() * 9000); | |
44 | + | const { selectedGame, selectedDate } = this.props; | |
45 | + | const { selectedSlot, name, contact } = this.state; | |
46 | + | ||
47 | + | this.props.bookSlot({ id: bookingID, name, contact, game: selectedGame.name, slot: selectedSlot, date: selectedDate }); | |
48 | + | this.props.saveDetails({ id: bookingID, name, contact }); | |
49 | + | alert(`Booking successful! Your ID is ${bookingID}`); | |
50 | + | this.props.navigate('/'); | |
51 | + | }; | |
52 | + | ||
53 | + | render() { | |
54 | + | const { selectedGame, selectedDate, bookingCheck } = this.props; | |
55 | + | const { selectedSlot, name, contact, errorStmt } = this.state; | |
56 | + | const slots = ['10AM', '11AM', '12PM', '1PM', '2PM', '3PM', '4PM']; | |
57 | + | ||
58 | + | const today = new Date().toISOString().split('T')[0]; | |
59 | + | const tomorrow = new Date(); | |
60 | + | tomorrow.setDate(new Date().getDate() + 1); | |
61 | + | const formattedTomorrow = tomorrow.toISOString().split('T')[0]; | |
62 | + | ||
63 | + | const renderSlots = () => ( | |
64 | + | <div className="slot_list"> | |
65 | + | {slots.map(slot => { | |
66 | + | const isBooked = bookingCheck.some(b => b.slot === slot && b.date === selectedDate); | |
67 | + | const isSelected = selectedSlot === slot; | |
68 | + | let color = 'green'; | |
69 | + | if (isBooked) color = 'red'; | |
70 | + | else if (isSelected) color = 'blue'; | |
71 | + | ||
72 | + | return ( | |
73 | + | <span | |
74 | + | key={slot} | |
75 | + | style={{ backgroundColor: color, margin: '5px', padding: '5px', display: 'inline-block' }} | |
76 | + | onClick={() => this.handleSlotClick(slot)} | |
77 | + | > | |
78 | + | <h4>{slot}</h4> | |
79 | + | </span> | |
80 | + | ); | |
81 | + | })} | |
82 | + | </div> | |
83 | + | ); | |
84 | + | ||
85 | + | return ( | |
86 | + | <div> | |
87 | + | <header> | |
88 | + | <h2>{selectedGame.name}</h2> | |
89 | + | <p>{selectedDate}</p> | |
90 | + | </header> | |
91 | + | <button onClick={() => this.props.navigate('/')}>Back</button> | |
92 | + | {selectedDate === today && <p>Booking has been closed. Book your slot for {formattedTomorrow}</p>} | |
93 | + | {selectedDate === formattedTomorrow && ( | |
94 | + | <> | |
95 | + | {renderSlots()} | |
96 | + | <input id="contact" placeholder="Name" value={name} onChange={(e) => this.setState({ name: e.target.value })} /> | |
97 | + | <input id="contact" placeholder="Contact" value={contact} onChange={(e) => this.setState({ contact: e.target.value })} /> | |
98 | + | <button id="book_button" onClick={this.handleBook}>Book Now</button> | |
99 | + | {errorStmt && <p>{errorStmt}</p>} | |
100 | + | </> | |
101 | + | )} | |
102 | + | {selectedDate > formattedTomorrow && <p>Booking is not opened yet</p>} | |
103 | + | </div> | |
104 | + | ); | |
105 | + | } | |
106 | + | } | |
107 | + | ||
108 | + | const mapStateToProps = (state) => ({ | |
109 | + | selectedGame: state.selectedGame[0] || {}, | |
110 | + | selectedDate: state.selectedDate, | |
111 | + | bookingCheck: state.bookingCheck, | |
112 | + | }); | |
113 | + | ||
114 | + | const mapDispatchToProps = { | |
115 | + | bookSlot, | |
116 | + | saveDetails, | |
117 | + | selectSlot, | |
118 | + | }; | |
119 | + | ||
120 | + | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Booking)); |
Home(file created)
@@ -0,0 +1,50 @@ | |||
1 | + | import React, { Component } from 'react'; | |
2 | + | import { connect } from 'react-redux'; | |
3 | + | import { selectGame } from '../Action/action'; | |
4 | + | import { withRouter } from './withRouter'; | |
5 | + | ||
6 | + | class Games extends Component { | |
7 | + | componentDidMount() { | |
8 | + | this.props.selectGame(null); | |
9 | + | } | |
10 | + | ||
11 | + | handlebook = (game) => { | |
12 | + | this.props.selectGame(game); | |
13 | + | this.props.navigate('/book'); | |
14 | + | }; | |
15 | + | ||
16 | + | handleSearch = () => { | |
17 | + | this.props.navigate('/search'); | |
18 | + | }; | |
19 | + | ||
20 | + | render() { | |
21 | + | return ( | |
22 | + | <div> | |
23 | + | <header>Play Zone </header> | |
24 | + | <div className="Card"> | |
25 | + | <ul> | |
26 | + | {this.props.Games.map((game, index) => ( | |
27 | + | <li key={index}> | |
28 | + | {game.name} | |
29 | + | <button onClick={() => this.handlebook(game)}>Book Now</button> | |
30 | + | </li> | |
31 | + | ))} | |
32 | + | </ul> | |
33 | + | </div> | |
34 | + | <center> | |
35 | + | <button onClick={this.handleSearch}>Check your booking</button> | |
36 | + | </center> | |
37 | + | </div> | |
38 | + | ); | |
39 | + | } | |
40 | + | } | |
41 | + | ||
42 | + | const mapStateToProps = (state) => ({ | |
43 | + | Games: state.Games, | |
44 | + | }); | |
45 | + | ||
46 | + | const mapDispatchToProps = { | |
47 | + | selectGame, | |
48 | + | }; | |
49 | + | ||
50 | + | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Games)); |
Reducer(file created)
@@ -0,0 +1,55 @@ | |||
1 | + | import { | |
2 | + | SELECT_GAME, | |
3 | + | SELECT_DATE, | |
4 | + | SELECT_SLOT, | |
5 | + | BOOK_SLOT, | |
6 | + | SAVE_DETAILS | |
7 | + | } from '../Action/action'; | |
8 | + | ||
9 | + | import BasketBall from './basket_ball.jpeg'; | |
10 | + | import VolleyBall from './volleyBall.jpeg'; | |
11 | + | import FootBall from './footBall.jpeg'; | |
12 | + | ||
13 | + | const bookSlot1 = [ | |
14 | + | { id: 1, startTime: "09.00 A.M", endTime: "10.00 A.M", slotStatus: "btn btn-success" }, | |
15 | + | { id: 2, startTime: "10.00 A.M", endTime: "11.00 A.M", slotStatus: "btn btn-success" }, | |
16 | + | { id: 3, startTime: "11.00 A.M", endTime: "12.00 P.M", slotStatus: "btn btn-success" }, | |
17 | + | { id: 4, startTime: "12.00 P.M", endTime: "01.00 P.M", slotStatus: "btn btn-success" }, | |
18 | + | { id: 5, startTime: "01.00 P.M", endTime: "02.00 P.M", slotStatus: "btn btn-success" }, | |
19 | + | { id: 6, startTime: "02.00 P.M", endTime: "03.00 P.M", slotStatus: "btn btn-success" }, | |
20 | + | { id: 7, startTime: "03.00 P.M", endTime: "04.00 P.M", slotStatus: "btn btn-success" }, | |
21 | + | { id: 8, startTime: "04.00 P.M", endTime: "05.00 P.M", slotStatus: "btn btn-success" }, | |
22 | + | { id: 9, startTime: "05.00 P.M", endTime: "06.00 P.M", slotStatus: "btn btn-success" } | |
23 | + | ]; | |
24 | + | ||
25 | + | const initialState = { | |
26 | + | Games: [ | |
27 | + | { id: 0, src: BasketBall, name: "BasketBall", slots: bookSlot1 }, | |
28 | + | { id: 1, src: VolleyBall, name: "VolleyBall", slots: bookSlot1 }, | |
29 | + | { id: 2, src: FootBall, name: "FootBall", slots: bookSlot1 } | |
30 | + | ], | |
31 | + | selectedGame: [], | |
32 | + | selectedDate: new Date(new Date().setDate(new Date().getDate() + 1)), | |
33 | + | slotBooked: undefined, | |
34 | + | details: [], | |
35 | + | bookingCheck: [], | |
36 | + | }; | |
37 | + | ||
38 | + | const reducer = (state = initialState, action) => { | |
39 | + | switch (action.type) { | |
40 | + | case SELECT_GAME: | |
41 | + | return { ...state, selectedGame: [action.payload] }; | |
42 | + | case SELECT_DATE: | |
43 | + | return { ...state, selectedDate: action.payload }; | |
44 | + | case SELECT_SLOT: | |
45 | + | return { ...state, slotBooked: action.payload }; | |
46 | + | case BOOK_SLOT: | |
47 | + | return { ...state, bookingCheck: [...state.bookingCheck, action.payload] }; | |
48 | + | case SAVE_DETAILS: | |
49 | + | return { ...state, details: [...state.details, action.payload] }; | |
50 | + | default: | |
51 | + | return state; | |
52 | + | } | |
53 | + | }; | |
54 | + | ||
55 | + | export default reducer; |
Search(file created)
@@ -0,0 +1,44 @@ | |||
1 | + | import React, { useState } from 'react'; | |
2 | + | import { useSelector } from 'react-redux'; | |
3 | + | import { useNavigate } from 'react-router-dom'; | |
4 | + | ||
5 | + | const Search = () => { | |
6 | + | const { bookingCheck } = useSelector((state) => state); | |
7 | + | const [searchId, setSearchId] = useState(''); | |
8 | + | const [foundBooking, setFoundBooking] = useState(null); | |
9 | + | const navigate = useNavigate(); | |
10 | + | ||
11 | + | const handleSearch = () => { | |
12 | + | const match = bookingCheck.find(b => b.id.toString() === searchId.trim()); | |
13 | + | setFoundBooking(match || 'not_found'); | |
14 | + | }; | |
15 | + | ||
16 | + | return ( | |
17 | + | <div> | |
18 | + | <h2>Search Booking</h2> | |
19 | + | <input | |
20 | + | type="text" | |
21 | + | placeholder="Enter Booking ID" | |
22 | + | value={searchId} | |
23 | + | onChange={(e) => setSearchId(e.target.value)} | |
24 | + | /> | |
25 | + | <button onClick={handleSearch}>Search</button> | |
26 | + | <button onClick={() => navigate('/')}>Back</button> | |
27 | + | ||
28 | + | {bookingCheck.length === 0 && <p>No Booking happened yet</p>} | |
29 | + | {foundBooking === 'not_found' && <p>No Booking Found</p>} | |
30 | + | {foundBooking && foundBooking !== 'not_found' && ( | |
31 | + | <div style={{ marginTop: '10px' }}> | |
32 | + | <p>ID: {foundBooking.id}</p> | |
33 | + | <p>Name: {foundBooking.name}</p> | |
34 | + | <p>Contact: {foundBooking.contact}</p> | |
35 | + | <p>Game: {foundBooking.game}</p> | |
36 | + | <p>Slot: {foundBooking.slot}</p> | |
37 | + | <p>Date: {foundBooking.date}</p> | |
38 | + | </div> | |
39 | + | )} | |
40 | + | </div> | |
41 | + | ); | |
42 | + | }; | |
43 | + | ||
44 | + | export default Search; |
Slot(file created)
@@ -0,0 +1,29 @@ | |||
1 | + | import React, { Component } from 'react'; | |
2 | + | ||
3 | + | class Slots extends Component { | |
4 | + | render() { | |
5 | + | const slots = [ | |
6 | + | "09.00 A.M - 10.00 A.M", | |
7 | + | "10.00 A.M - 11.00 A.M", | |
8 | + | "11.00 A.M - 12.00 P.M", | |
9 | + | "12.00 P.M - 01.00 P.M", | |
10 | + | "01.00 P.M - 02.00 P.M", | |
11 | + | "02.00 P.M - 03.00 P.M", | |
12 | + | "03.00 P.M - 04.00 P.M", | |
13 | + | "04.00 P.M - 05.00 P.M", | |
14 | + | "05.00 P.M - 06.00 P.M" | |
15 | + | ]; | |
16 | + | ||
17 | + | return ( | |
18 | + | <div className="slot_list"> | |
19 | + | {slots.map((slot, index) => ( | |
20 | + | <span key={index} onClick={() => console.log(`Slot ${index} clicked`)}> | |
21 | + | <h4>{slot}</h4> | |
22 | + | </span> | |
23 | + | ))} | |
24 | + | </div> | |
25 | + | ); | |
26 | + | } | |
27 | + | } | |
28 | + | ||
29 | + | export default Slots; |